@stackfactor/agent-utils 1.1.0 → 1.1.2
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/cjs/agentProto.d.ts +19 -0
- package/dist/cjs/agentProto.d.ts.map +1 -0
- package/dist/cjs/agentProto.js +98 -0
- package/dist/cjs/client.d.ts +41 -0
- package/dist/cjs/client.d.ts.map +1 -0
- package/dist/cjs/client.js +131 -0
- package/dist/cjs/index.d.ts +3 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +3 -1
- package/dist/cjs/langChain.d.ts.map +1 -1
- package/dist/cjs/langChain.js +71 -30
- package/dist/cjs/serve.d.ts.map +1 -1
- package/dist/cjs/serve.js +2 -54
- package/dist/esm/agentProto.d.ts +19 -0
- package/dist/esm/agentProto.d.ts.map +1 -0
- package/dist/esm/agentProto.js +60 -0
- package/dist/esm/client.d.ts +41 -0
- package/dist/esm/client.d.ts.map +1 -0
- package/dist/esm/client.js +94 -0
- package/dist/esm/index.d.ts +3 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +2 -0
- package/dist/esm/langChain.d.ts.map +1 -1
- package/dist/esm/langChain.js +71 -30
- package/dist/esm/serve.d.ts.map +1 -1
- package/dist/esm/serve.js +1 -53
- package/package.json +2 -2
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as grpc from "@grpc/grpc-js";
|
|
2
|
+
/**
|
|
3
|
+
* gRPC contract shared by the entire agent fleet — the `serve()` server AND the
|
|
4
|
+
* relay client. `data`/`config`/`request` are carried as JSON strings so
|
|
5
|
+
* arbitrary payloads need no proto schema churn. `Execute` is server-streaming:
|
|
6
|
+
* zero or more `Progress` frames (driven by the agent's `onProgress`) followed
|
|
7
|
+
* by exactly one `Result` or `Error`.
|
|
8
|
+
*/
|
|
9
|
+
export declare const PROTO = "\nsyntax = \"proto3\";\npackage stackfactor.agent.v1;\n\nservice Agent {\n rpc Execute(ExecuteRequest) returns (stream Update);\n}\n\nmessage ExecuteRequest {\n string content_type = 1;\n string data_json = 2;\n string config_json = 3;\n string request_json = 4;\n int32 event = 5;\n}\n\nmessage Update {\n oneof payload {\n Progress progress = 1;\n Result result = 2;\n ErrorInfo error = 3;\n }\n}\n\nmessage Progress { int32 progress = 1; string message = 2; }\nmessage Result { string result_json = 1; }\nmessage ErrorInfo { int32 code = 1; string message = 2; }\n";
|
|
10
|
+
/**
|
|
11
|
+
* Loads the Agent proto package. proto-loader reads from a file, so the embedded
|
|
12
|
+
* schema is written to a temp path — keeps the package self-contained across the
|
|
13
|
+
* cjs/esm dual build. Returns the loaded package (server uses
|
|
14
|
+
* `.stackfactor.agent.v1.Agent.service`; client uses the `Agent` constructor).
|
|
15
|
+
*/
|
|
16
|
+
export declare const loadAgentPackage: () => any;
|
|
17
|
+
/** The Agent gRPC service definition (for the `serve()` server). */
|
|
18
|
+
export declare const loadAgentService: () => grpc.ServiceDefinition;
|
|
19
|
+
//# sourceMappingURL=agentProto.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agentProto.d.ts","sourceRoot":"","sources":["../../src/agentProto.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,eAAe,CAAC;AAMtC;;;;;;GAMG;AACH,eAAO,MAAM,KAAK,smBA2BjB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,QAAO,GAWnC,CAAC;AAEF,oEAAoE;AACpE,eAAO,MAAM,gBAAgB,QAAO,IAAI,CAAC,iBACc,CAAC"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.loadAgentService = exports.loadAgentPackage = exports.PROTO = void 0;
|
|
37
|
+
const grpc = __importStar(require("@grpc/grpc-js"));
|
|
38
|
+
const protoLoader = __importStar(require("@grpc/proto-loader"));
|
|
39
|
+
const node_fs_1 = require("node:fs");
|
|
40
|
+
const node_path_1 = require("node:path");
|
|
41
|
+
const node_os_1 = require("node:os");
|
|
42
|
+
/**
|
|
43
|
+
* gRPC contract shared by the entire agent fleet — the `serve()` server AND the
|
|
44
|
+
* relay client. `data`/`config`/`request` are carried as JSON strings so
|
|
45
|
+
* arbitrary payloads need no proto schema churn. `Execute` is server-streaming:
|
|
46
|
+
* zero or more `Progress` frames (driven by the agent's `onProgress`) followed
|
|
47
|
+
* by exactly one `Result` or `Error`.
|
|
48
|
+
*/
|
|
49
|
+
exports.PROTO = `
|
|
50
|
+
syntax = "proto3";
|
|
51
|
+
package stackfactor.agent.v1;
|
|
52
|
+
|
|
53
|
+
service Agent {
|
|
54
|
+
rpc Execute(ExecuteRequest) returns (stream Update);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
message ExecuteRequest {
|
|
58
|
+
string content_type = 1;
|
|
59
|
+
string data_json = 2;
|
|
60
|
+
string config_json = 3;
|
|
61
|
+
string request_json = 4;
|
|
62
|
+
int32 event = 5;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
message Update {
|
|
66
|
+
oneof payload {
|
|
67
|
+
Progress progress = 1;
|
|
68
|
+
Result result = 2;
|
|
69
|
+
ErrorInfo error = 3;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
message Progress { int32 progress = 1; string message = 2; }
|
|
74
|
+
message Result { string result_json = 1; }
|
|
75
|
+
message ErrorInfo { int32 code = 1; string message = 2; }
|
|
76
|
+
`;
|
|
77
|
+
/**
|
|
78
|
+
* Loads the Agent proto package. proto-loader reads from a file, so the embedded
|
|
79
|
+
* schema is written to a temp path — keeps the package self-contained across the
|
|
80
|
+
* cjs/esm dual build. Returns the loaded package (server uses
|
|
81
|
+
* `.stackfactor.agent.v1.Agent.service`; client uses the `Agent` constructor).
|
|
82
|
+
*/
|
|
83
|
+
const loadAgentPackage = () => {
|
|
84
|
+
const file = (0, node_path_1.join)((0, node_os_1.tmpdir)(), "stackfactor-agent.v1.proto");
|
|
85
|
+
(0, node_fs_1.writeFileSync)(file, exports.PROTO);
|
|
86
|
+
const packageDefinition = protoLoader.loadSync(file, {
|
|
87
|
+
keepCase: true,
|
|
88
|
+
longs: String,
|
|
89
|
+
enums: String,
|
|
90
|
+
defaults: true,
|
|
91
|
+
oneofs: true,
|
|
92
|
+
});
|
|
93
|
+
return grpc.loadPackageDefinition(packageDefinition);
|
|
94
|
+
};
|
|
95
|
+
exports.loadAgentPackage = loadAgentPackage;
|
|
96
|
+
/** The Agent gRPC service definition (for the `serve()` server). */
|
|
97
|
+
const loadAgentService = () => (0, exports.loadAgentPackage)().stackfactor.agent.v1.Agent.service;
|
|
98
|
+
exports.loadAgentService = loadAgentService;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The fleet `Agent.Execute` request. `*_json` fields are JSON strings.
|
|
3
|
+
* `request_json` MUST include the caller's StackFactor session token as
|
|
4
|
+
* `authToken` — the agent validates it (via `serve()`'s auth gate) before
|
|
5
|
+
* running. This is distinct from the Cloud Run ID token (see `CallAgentOptions`).
|
|
6
|
+
*/
|
|
7
|
+
export interface AgentExecuteRequest {
|
|
8
|
+
content_type: string;
|
|
9
|
+
data_json: string;
|
|
10
|
+
config_json: string;
|
|
11
|
+
request_json: string;
|
|
12
|
+
event: number;
|
|
13
|
+
}
|
|
14
|
+
export interface CallAgentOptions {
|
|
15
|
+
/**
|
|
16
|
+
* Google ID token (audience = the agent's Cloud Run URL) to get past Cloud
|
|
17
|
+
* Run's `--no-allow-unauthenticated` ingress. Attached as `authorization:
|
|
18
|
+
* Bearer` metadata. The agent never sees it; ingress consumes it.
|
|
19
|
+
*/
|
|
20
|
+
idToken?: string;
|
|
21
|
+
/** Called for each streamed `Progress` frame (e.g. to forward to a socket). */
|
|
22
|
+
onProgress?: (update: {
|
|
23
|
+
progress: number;
|
|
24
|
+
message: string;
|
|
25
|
+
}) => void;
|
|
26
|
+
/** Abort the RPC (e.g. the frontend socket dropped) → stops the agent's LLM. */
|
|
27
|
+
signal?: AbortSignal;
|
|
28
|
+
/** Call deadline; defaults to 900s to match Cloud Run's max request timeout. */
|
|
29
|
+
deadlineMs?: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Calls a deployed agent's `Agent.Execute` over gRPC server-streaming. Forwards
|
|
33
|
+
* each `Progress` frame to `onProgress`, resolves with the parsed `result_json`
|
|
34
|
+
* on `Result`, and rejects (with `error.code`) on `ErrorInfo`. Caller-cancel via
|
|
35
|
+
* `options.signal` cancels the RPC.
|
|
36
|
+
*
|
|
37
|
+
* @param agentUrl - The agent's Cloud Run URL (https://…run.app).
|
|
38
|
+
* @param request - The `ExecuteRequest` (its `request_json` carries `authToken`).
|
|
39
|
+
*/
|
|
40
|
+
export declare const callAgent: (agentUrl: string, request: AgentExecuteRequest, options?: CallAgentOptions) => Promise<any>;
|
|
41
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACrE,gFAAgF;IAChF,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,gFAAgF;IAChF,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAqCD;;;;;;;;GAQG;AACH,eAAO,MAAM,SAAS,GACpB,UAAU,MAAM,EAChB,SAAS,mBAAmB,EAC5B,UAAS,gBAAqB,KAC7B,OAAO,CAAC,GAAG,CAyDV,CAAC"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.callAgent = void 0;
|
|
37
|
+
const grpc = __importStar(require("@grpc/grpc-js"));
|
|
38
|
+
const agentProto_js_1 = require("./agentProto.js");
|
|
39
|
+
const DEFAULT_DEADLINE_MS = 900_000;
|
|
40
|
+
const safeParse = (value, fallback) => {
|
|
41
|
+
if (!value)
|
|
42
|
+
return fallback;
|
|
43
|
+
try {
|
|
44
|
+
return JSON.parse(value);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return fallback;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
/** Turns an `ErrorInfo` frame into an Error carrying the agent's `code`. */
|
|
51
|
+
const agentError = (frame) => {
|
|
52
|
+
const error = new Error(frame?.message || "Agent error");
|
|
53
|
+
error.code = frame?.code;
|
|
54
|
+
return error;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Channel credentials for an authenticated Cloud Run agent: TLS (Cloud Run
|
|
58
|
+
* terminates at the edge) plus per-call metadata carrying the ID token.
|
|
59
|
+
*/
|
|
60
|
+
const buildCredentials = (idToken) => {
|
|
61
|
+
const ssl = grpc.credentials.createSsl();
|
|
62
|
+
if (!idToken) {
|
|
63
|
+
return ssl;
|
|
64
|
+
}
|
|
65
|
+
const callCreds = grpc.credentials.createFromMetadataGenerator((_ctx, cb) => {
|
|
66
|
+
const metadata = new grpc.Metadata();
|
|
67
|
+
metadata.add("authorization", `Bearer ${idToken}`);
|
|
68
|
+
cb(null, metadata);
|
|
69
|
+
});
|
|
70
|
+
return grpc.credentials.combineChannelCredentials(ssl, callCreds);
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Calls a deployed agent's `Agent.Execute` over gRPC server-streaming. Forwards
|
|
74
|
+
* each `Progress` frame to `onProgress`, resolves with the parsed `result_json`
|
|
75
|
+
* on `Result`, and rejects (with `error.code`) on `ErrorInfo`. Caller-cancel via
|
|
76
|
+
* `options.signal` cancels the RPC.
|
|
77
|
+
*
|
|
78
|
+
* @param agentUrl - The agent's Cloud Run URL (https://…run.app).
|
|
79
|
+
* @param request - The `ExecuteRequest` (its `request_json` carries `authToken`).
|
|
80
|
+
*/
|
|
81
|
+
const callAgent = (agentUrl, request, options = {}) => new Promise((resolve, reject) => {
|
|
82
|
+
const loaded = (0, agentProto_js_1.loadAgentPackage)();
|
|
83
|
+
const url = new URL(agentUrl);
|
|
84
|
+
const address = `${url.hostname}:${url.port || "443"}`;
|
|
85
|
+
const client = new loaded.stackfactor.agent.v1.Agent(address, buildCredentials(options.idToken));
|
|
86
|
+
const stream = client.Execute(request, {
|
|
87
|
+
deadline: Date.now() + (options.deadlineMs ?? DEFAULT_DEADLINE_MS),
|
|
88
|
+
});
|
|
89
|
+
let settled = false;
|
|
90
|
+
const settle = (run) => {
|
|
91
|
+
if (settled) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
settled = true;
|
|
95
|
+
try {
|
|
96
|
+
client.close();
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
// ignore close errors
|
|
100
|
+
}
|
|
101
|
+
run();
|
|
102
|
+
};
|
|
103
|
+
if (options.signal) {
|
|
104
|
+
if (options.signal.aborted) {
|
|
105
|
+
stream.cancel();
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
options.signal.addEventListener("abort", () => stream.cancel(), {
|
|
109
|
+
once: true,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
stream.on("data", (update) => {
|
|
114
|
+
if (update.progress) {
|
|
115
|
+
options.onProgress?.({
|
|
116
|
+
progress: update.progress.progress ?? 0,
|
|
117
|
+
message: update.progress.message ?? "",
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
else if (update.result) {
|
|
121
|
+
const result = safeParse(update.result.result_json, null);
|
|
122
|
+
settle(() => resolve(result));
|
|
123
|
+
}
|
|
124
|
+
else if (update.error) {
|
|
125
|
+
settle(() => reject(agentError(update.error)));
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
stream.on("error", (error) => settle(() => reject(error)));
|
|
129
|
+
stream.on("end", () => settle(() => reject(new Error("Agent stream ended without a result or error"))));
|
|
130
|
+
});
|
|
131
|
+
exports.callAgent = callAgent;
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -3,11 +3,14 @@ import errorHandling from "./errorHandling.js";
|
|
|
3
3
|
import langChain from "./langChain.js";
|
|
4
4
|
import logger from "./logger.js";
|
|
5
5
|
import { serve } from "./serve.js";
|
|
6
|
+
import { callAgent } from "./client.js";
|
|
6
7
|
import * as runtimeContext from "./runtimeContext.js";
|
|
7
8
|
export { constants };
|
|
8
9
|
export { errorHandling };
|
|
9
10
|
export { langChain };
|
|
10
11
|
export { logger };
|
|
11
12
|
export { serve };
|
|
13
|
+
export { callAgent };
|
|
14
|
+
export type { AgentExecuteRequest, CallAgentOptions } from "./client.js";
|
|
12
15
|
export { runtimeContext };
|
|
13
16
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/cjs/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,YAAY,CAAC;AACnC,OAAO,aAAa,MAAM,oBAAoB,CAAC;AAC/C,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,OAAO,EAAE,aAAa,EAAE,CAAC;AAEzB,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,OAAO,EAAE,MAAM,EAAE,CAAC;AAElB,OAAO,EAAE,KAAK,EAAE,CAAC;AAEjB,OAAO,EAAE,cAAc,EAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,YAAY,CAAC;AACnC,OAAO,aAAa,MAAM,oBAAoB,CAAC;AAC/C,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,OAAO,EAAE,aAAa,EAAE,CAAC;AAEzB,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,OAAO,EAAE,MAAM,EAAE,CAAC;AAElB,OAAO,EAAE,KAAK,EAAE,CAAC;AAEjB,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,YAAY,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEzE,OAAO,EAAE,cAAc,EAAE,CAAC"}
|
package/dist/cjs/index.js
CHANGED
|
@@ -36,7 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
36
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.runtimeContext = exports.serve = exports.logger = exports.langChain = exports.errorHandling = exports.constants = void 0;
|
|
39
|
+
exports.runtimeContext = exports.callAgent = exports.serve = exports.logger = exports.langChain = exports.errorHandling = exports.constants = void 0;
|
|
40
40
|
const const_js_1 = __importDefault(require("./const.js"));
|
|
41
41
|
exports.constants = const_js_1.default;
|
|
42
42
|
const errorHandling_js_1 = __importDefault(require("./errorHandling.js"));
|
|
@@ -47,5 +47,7 @@ const logger_js_1 = __importDefault(require("./logger.js"));
|
|
|
47
47
|
exports.logger = logger_js_1.default;
|
|
48
48
|
const serve_js_1 = require("./serve.js");
|
|
49
49
|
Object.defineProperty(exports, "serve", { enumerable: true, get: function () { return serve_js_1.serve; } });
|
|
50
|
+
const client_js_1 = require("./client.js");
|
|
51
|
+
Object.defineProperty(exports, "callAgent", { enumerable: true, get: function () { return client_js_1.callAgent; } });
|
|
50
52
|
const runtimeContext = __importStar(require("./runtimeContext.js"));
|
|
51
53
|
exports.runtimeContext = runtimeContext;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"langChain.d.ts","sourceRoot":"","sources":["../../src/langChain.ts"],"names":[],"mappings":";0CAiD6C,GAAG,KAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"langChain.d.ts","sourceRoot":"","sources":["../../src/langChain.ts"],"names":[],"mappings":";0CAiD6C,GAAG,KAAG,IAAI;wBAyhB/C,MAAM,aACD,MAAM,gBACH,MAAM,SACb,GAAG,EAAE,kBACI,GAAG,UACX,GAAG,KACV,GAAG;sBAyBG,GAAG,UACF,MAAM,UACN,GAAG,eACC,QAAQ,GAAG,IAAI,KAC1B,OAAO,CAAC,GAAG,CAAC;oCAqXF,MAAM,UACT,GAAG,UACH,GAAG,oBACO,GAAG,eACT,MAAM,eACN,MAAM,wBACG,OAAO,WACpB,GAAG,cACA,MAAM,UACV,GAAG,EAAE,KACX,OAAO,CAAC,GAAG,CAAC;sDAosBF,MAAM,UACT,GAAG,UACH,MAAM,YACL,GAAG,KACX,OAAO,CAAC,GAAG,CAAC;0CAn+B8B,GAAG,KAAG,MAAM;mCAoBxC,MAAM,mBACJ,MAAM,EAAE,KACxB,MAAM;;AAwgCT,wBAQE"}
|
package/dist/cjs/langChain.js
CHANGED
|
@@ -68,40 +68,81 @@ const recordCost = (cost) => {
|
|
|
68
68
|
}
|
|
69
69
|
};
|
|
70
70
|
/**
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
71
|
+
* Reads a per-model rate from the flat cost constants the integration defines
|
|
72
|
+
* in its `config.yaml` (exposed on the config object), e.g.
|
|
73
|
+
* `claude-opus-4-7-input-token-costs`. Returns `null` when the constant is
|
|
74
|
+
* absent or not numeric, in which case cost recording becomes a no-op (the
|
|
75
|
+
* call still succeeds — pricing is the integration's configuration concern).
|
|
75
76
|
*/
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
if (!pricing)
|
|
77
|
+
const getModelRate = (modelName, config, kind) => {
|
|
78
|
+
if (!config || !modelName)
|
|
79
79
|
return null;
|
|
80
|
-
|
|
80
|
+
const rate = Number(config[`${modelName}-${kind}-costs`]);
|
|
81
|
+
return Number.isFinite(rate) ? rate : null;
|
|
81
82
|
};
|
|
82
83
|
/**
|
|
83
|
-
*
|
|
84
|
-
*
|
|
84
|
+
* Accumulates the per-model usage breakdown on `global.quota.byModel` so the
|
|
85
|
+
* agent can report input/output token counts and image spend per model to the
|
|
86
|
+
* UI. No-ops when the quota global is absent.
|
|
85
87
|
*/
|
|
86
|
-
const
|
|
88
|
+
const recordModelBreakdown = (modelName, inputCost, outputCost, imageCost, inputTokens = 0, outputTokens = 0) => {
|
|
89
|
+
const quota = globalThis.quota;
|
|
90
|
+
if (!quota || !modelName)
|
|
91
|
+
return;
|
|
92
|
+
if (!quota.byModel || typeof quota.byModel !== "object")
|
|
93
|
+
quota.byModel = {};
|
|
94
|
+
const entry = (quota.byModel[modelName] ||= {
|
|
95
|
+
inputCost: 0,
|
|
96
|
+
outputCost: 0,
|
|
97
|
+
imageCost: 0,
|
|
98
|
+
inputTokens: 0,
|
|
99
|
+
outputTokens: 0,
|
|
100
|
+
});
|
|
101
|
+
// Entries created by older versions of this module lack the token counters.
|
|
102
|
+
if (typeof entry.inputTokens !== "number")
|
|
103
|
+
entry.inputTokens = 0;
|
|
104
|
+
if (typeof entry.outputTokens !== "number")
|
|
105
|
+
entry.outputTokens = 0;
|
|
106
|
+
if (Number.isFinite(inputCost) && inputCost > 0)
|
|
107
|
+
entry.inputCost += inputCost;
|
|
108
|
+
if (Number.isFinite(outputCost) && outputCost > 0)
|
|
109
|
+
entry.outputCost += outputCost;
|
|
110
|
+
if (Number.isFinite(imageCost) && imageCost > 0)
|
|
111
|
+
entry.imageCost += imageCost;
|
|
112
|
+
if (Number.isFinite(inputTokens) && inputTokens > 0)
|
|
113
|
+
entry.inputTokens += inputTokens;
|
|
114
|
+
if (Number.isFinite(outputTokens) && outputTokens > 0)
|
|
115
|
+
entry.outputTokens += outputTokens;
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* Computes and records the USD cost of a text LLM call from the
|
|
119
|
+
* `<model>-input-token-costs` / `<model>-output-token-costs` constants
|
|
120
|
+
* (dollars per million tokens). Updates both the session total
|
|
121
|
+
* (`quota.usedThisSession` / `quota.remaining`) and the per-model breakdown
|
|
122
|
+
* (`quota.byModel`).
|
|
123
|
+
*/
|
|
124
|
+
const recordTextCost = (modelName, usage, config) => {
|
|
87
125
|
if (!usage)
|
|
88
|
-
return
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const
|
|
93
|
-
const
|
|
94
|
-
|
|
126
|
+
return;
|
|
127
|
+
const inputRate = getModelRate(modelName, config, "input-token") || 0;
|
|
128
|
+
const outputRate = getModelRate(modelName, config, "output-token") || 0;
|
|
129
|
+
const inputTokens = usage.input_tokens || 0;
|
|
130
|
+
const outputTokens = usage.output_tokens || 0;
|
|
131
|
+
const inputCost = (inputTokens / 1_000_000) * inputRate;
|
|
132
|
+
const outputCost = (outputTokens / 1_000_000) * outputRate;
|
|
133
|
+
recordCost(inputCost + outputCost);
|
|
134
|
+
recordModelBreakdown(modelName, inputCost, outputCost, 0, inputTokens, outputTokens);
|
|
95
135
|
};
|
|
96
136
|
/**
|
|
97
|
-
* Computes USD cost
|
|
98
|
-
*
|
|
137
|
+
* Computes and records the USD cost of an image generation call from the
|
|
138
|
+
* `<model>-image-costs` constant (dollars per generated image). Updates both
|
|
139
|
+
* the session total and the per-model breakdown.
|
|
99
140
|
*/
|
|
100
|
-
const
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
141
|
+
const recordImageCost = (modelName, numImages, config) => {
|
|
142
|
+
const rate = getModelRate(modelName, config, "image") || 0;
|
|
143
|
+
const imageCost = (numImages || 0) * rate;
|
|
144
|
+
recordCost(imageCost);
|
|
145
|
+
recordModelBreakdown(modelName, 0, 0, imageCost);
|
|
105
146
|
};
|
|
106
147
|
/**
|
|
107
148
|
* Extracts a normalized token-usage object from a single LangChain `invoke()`
|
|
@@ -569,7 +610,7 @@ const runAgent = async (agent, prompt, config, onProgress = null) => {
|
|
|
569
610
|
throw err;
|
|
570
611
|
}
|
|
571
612
|
}
|
|
572
|
-
|
|
613
|
+
recordTextCost(modelName, sumAgentResponseUsage(response), config);
|
|
573
614
|
const endTime = Date.now();
|
|
574
615
|
const duration = endTime - startTime;
|
|
575
616
|
logger_js_1.default.log(null, logger_js_1.default.levels.info, `Agent "${agent.options?.name}" completed in ${Math.round(duration / 1000)} seconds.`);
|
|
@@ -1044,7 +1085,7 @@ const runPromptWithModel = async (modelName, config, prompt, onProgressReport, m
|
|
|
1044
1085
|
throw err;
|
|
1045
1086
|
}
|
|
1046
1087
|
}
|
|
1047
|
-
|
|
1088
|
+
recordTextCost(modelName, streamUsage, config);
|
|
1048
1089
|
if (!rawContent) {
|
|
1049
1090
|
throw errorHandling_js_1.default.create(const_js_1.default.HTTP_CODES.INTERNAL_SERVER_ERROR, "LLM returned no content");
|
|
1050
1091
|
}
|
|
@@ -1144,7 +1185,7 @@ const runPromptWithModel = async (modelName, config, prompt, onProgressReport, m
|
|
|
1144
1185
|
throw err;
|
|
1145
1186
|
}
|
|
1146
1187
|
}
|
|
1147
|
-
|
|
1188
|
+
recordTextCost(modelName, extractUsageFromInvoke(response), config);
|
|
1148
1189
|
const rawContent = response?.content || response;
|
|
1149
1190
|
// If not expecting JSON, return raw content directly
|
|
1150
1191
|
if (!expectsJsonResponse) {
|
|
@@ -1252,7 +1293,7 @@ const generateImageWithOpenAI = async (modelName, config, prompt, options) => {
|
|
|
1252
1293
|
}
|
|
1253
1294
|
assertQuotaAvailable();
|
|
1254
1295
|
const response = await openai.images.generate(requestParams);
|
|
1255
|
-
|
|
1296
|
+
recordImageCost(modelName, response.data?.length || n, config);
|
|
1256
1297
|
// Format response based on number of images
|
|
1257
1298
|
if (n === 1) {
|
|
1258
1299
|
const imageData = response.data[0];
|
|
@@ -1369,7 +1410,7 @@ const generateImageWithGoogle = async (modelName, config, prompt, options) => {
|
|
|
1369
1410
|
if (images.length === 0) {
|
|
1370
1411
|
throw errorHandling_js_1.default.create(const_js_1.default.HTTP_CODES.INTERNAL_SERVER_ERROR, `No images were generated by ${modelName}`);
|
|
1371
1412
|
}
|
|
1372
|
-
|
|
1413
|
+
recordImageCost(modelName, images.length, config);
|
|
1373
1414
|
if (numberOfImages === 1 || images.length === 1) {
|
|
1374
1415
|
return images[0];
|
|
1375
1416
|
}
|
package/dist/cjs/serve.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/serve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/serve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,eAAe,CAAC;AAMtC;;;;;GAKG;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;AAE/D;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,EAAE,GAAG,KAAK,OAAO,CAAC;IAAE,IAAI,EAAE,GAAG,CAAC;IAAC,MAAM,EAAE,GAAG,CAAA;CAAE,CAAC,CAAC;AAElF,MAAM,WAAW,YAAY;IAC3B,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wFAAwF;IACxF,YAAY,CAAC,EAAE,aAAa,CAAC;CAC9B;AAkDD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,KAAK,GAAI,MAAM,SAAS,EAAE,UAAS,YAAiB,KAAG,IAAI,CAAC,MAsGxE,CAAC"}
|
package/dist/cjs/serve.js
CHANGED
|
@@ -38,12 +38,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.serve = void 0;
|
|
40
40
|
const grpc = __importStar(require("@grpc/grpc-js"));
|
|
41
|
-
const protoLoader = __importStar(require("@grpc/proto-loader"));
|
|
42
41
|
const client_api_1 = require("@stackfactor/client-api");
|
|
43
|
-
const node_fs_1 = require("node:fs");
|
|
44
|
-
const node_path_1 = require("node:path");
|
|
45
|
-
const node_os_1 = require("node:os");
|
|
46
42
|
const logger_js_1 = __importDefault(require("./logger.js"));
|
|
43
|
+
const agentProto_js_1 = require("./agentProto.js");
|
|
47
44
|
const runtimeContext_js_1 = require("./runtimeContext.js");
|
|
48
45
|
/** Marks an auth failure so the handler can map it to gRPC UNAUTHENTICATED. */
|
|
49
46
|
class UnauthenticatedError extends Error {
|
|
@@ -66,55 +63,6 @@ const defaultAuthenticate = async (request) => {
|
|
|
66
63
|
throw new UnauthenticatedError(`Invalid auth token: ${error?.message ?? error}`);
|
|
67
64
|
}
|
|
68
65
|
};
|
|
69
|
-
/**
|
|
70
|
-
* gRPC contract shared by the entire agent fleet. `data`/`config`/`request` are
|
|
71
|
-
* carried as JSON strings so arbitrary payloads need no proto schema churn.
|
|
72
|
-
* `Execute` is server-streaming: zero or more `Progress` frames (driven by the
|
|
73
|
-
* agent's `onProgress`) followed by exactly one `Result` or `Error`.
|
|
74
|
-
*/
|
|
75
|
-
const PROTO = `
|
|
76
|
-
syntax = "proto3";
|
|
77
|
-
package stackfactor.agent.v1;
|
|
78
|
-
|
|
79
|
-
service Agent {
|
|
80
|
-
rpc Execute(ExecuteRequest) returns (stream Update);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
message ExecuteRequest {
|
|
84
|
-
string content_type = 1;
|
|
85
|
-
string data_json = 2;
|
|
86
|
-
string config_json = 3;
|
|
87
|
-
string request_json = 4;
|
|
88
|
-
int32 event = 5;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
message Update {
|
|
92
|
-
oneof payload {
|
|
93
|
-
Progress progress = 1;
|
|
94
|
-
Result result = 2;
|
|
95
|
-
ErrorInfo error = 3;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
message Progress { int32 progress = 1; string message = 2; }
|
|
100
|
-
message Result { string result_json = 1; }
|
|
101
|
-
message ErrorInfo { int32 code = 1; string message = 2; }
|
|
102
|
-
`;
|
|
103
|
-
const loadAgentService = () => {
|
|
104
|
-
// proto-loader reads from a file; write the embedded schema to a temp path so
|
|
105
|
-
// the package stays self-contained across the cjs/esm dual build.
|
|
106
|
-
const file = (0, node_path_1.join)((0, node_os_1.tmpdir)(), "stackfactor-agent.v1.proto");
|
|
107
|
-
(0, node_fs_1.writeFileSync)(file, PROTO);
|
|
108
|
-
const packageDefinition = protoLoader.loadSync(file, {
|
|
109
|
-
keepCase: true,
|
|
110
|
-
longs: String,
|
|
111
|
-
enums: String,
|
|
112
|
-
defaults: true,
|
|
113
|
-
oneofs: true,
|
|
114
|
-
});
|
|
115
|
-
const loaded = grpc.loadPackageDefinition(packageDefinition);
|
|
116
|
-
return loaded.stackfactor.agent.v1.Agent.service;
|
|
117
|
-
};
|
|
118
66
|
const safeParse = (value, fallback) => {
|
|
119
67
|
if (!value)
|
|
120
68
|
return fallback;
|
|
@@ -219,7 +167,7 @@ const serve = (main, options = {}) => {
|
|
|
219
167
|
void handle();
|
|
220
168
|
};
|
|
221
169
|
const server = new grpc.Server();
|
|
222
|
-
server.addService(loadAgentService(), { Execute: execute });
|
|
170
|
+
server.addService((0, agentProto_js_1.loadAgentService)(), { Execute: execute });
|
|
223
171
|
// Insecure: Cloud Run terminates TLS at the edge and forwards h2c to the
|
|
224
172
|
// container (requires the service to be deployed with --use-http2).
|
|
225
173
|
server.bindAsync(`${host}:${port}`, grpc.ServerCredentials.createInsecure(), (err, boundPort) => {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as grpc from "@grpc/grpc-js";
|
|
2
|
+
/**
|
|
3
|
+
* gRPC contract shared by the entire agent fleet — the `serve()` server AND the
|
|
4
|
+
* relay client. `data`/`config`/`request` are carried as JSON strings so
|
|
5
|
+
* arbitrary payloads need no proto schema churn. `Execute` is server-streaming:
|
|
6
|
+
* zero or more `Progress` frames (driven by the agent's `onProgress`) followed
|
|
7
|
+
* by exactly one `Result` or `Error`.
|
|
8
|
+
*/
|
|
9
|
+
export declare const PROTO = "\nsyntax = \"proto3\";\npackage stackfactor.agent.v1;\n\nservice Agent {\n rpc Execute(ExecuteRequest) returns (stream Update);\n}\n\nmessage ExecuteRequest {\n string content_type = 1;\n string data_json = 2;\n string config_json = 3;\n string request_json = 4;\n int32 event = 5;\n}\n\nmessage Update {\n oneof payload {\n Progress progress = 1;\n Result result = 2;\n ErrorInfo error = 3;\n }\n}\n\nmessage Progress { int32 progress = 1; string message = 2; }\nmessage Result { string result_json = 1; }\nmessage ErrorInfo { int32 code = 1; string message = 2; }\n";
|
|
10
|
+
/**
|
|
11
|
+
* Loads the Agent proto package. proto-loader reads from a file, so the embedded
|
|
12
|
+
* schema is written to a temp path — keeps the package self-contained across the
|
|
13
|
+
* cjs/esm dual build. Returns the loaded package (server uses
|
|
14
|
+
* `.stackfactor.agent.v1.Agent.service`; client uses the `Agent` constructor).
|
|
15
|
+
*/
|
|
16
|
+
export declare const loadAgentPackage: () => any;
|
|
17
|
+
/** The Agent gRPC service definition (for the `serve()` server). */
|
|
18
|
+
export declare const loadAgentService: () => grpc.ServiceDefinition;
|
|
19
|
+
//# sourceMappingURL=agentProto.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agentProto.d.ts","sourceRoot":"","sources":["../../src/agentProto.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,eAAe,CAAC;AAMtC;;;;;;GAMG;AACH,eAAO,MAAM,KAAK,smBA2BjB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,QAAO,GAWnC,CAAC;AAEF,oEAAoE;AACpE,eAAO,MAAM,gBAAgB,QAAO,IAAI,CAAC,iBACc,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import * as grpc from "@grpc/grpc-js";
|
|
2
|
+
import * as protoLoader from "@grpc/proto-loader";
|
|
3
|
+
import { writeFileSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
/**
|
|
7
|
+
* gRPC contract shared by the entire agent fleet — the `serve()` server AND the
|
|
8
|
+
* relay client. `data`/`config`/`request` are carried as JSON strings so
|
|
9
|
+
* arbitrary payloads need no proto schema churn. `Execute` is server-streaming:
|
|
10
|
+
* zero or more `Progress` frames (driven by the agent's `onProgress`) followed
|
|
11
|
+
* by exactly one `Result` or `Error`.
|
|
12
|
+
*/
|
|
13
|
+
export const PROTO = `
|
|
14
|
+
syntax = "proto3";
|
|
15
|
+
package stackfactor.agent.v1;
|
|
16
|
+
|
|
17
|
+
service Agent {
|
|
18
|
+
rpc Execute(ExecuteRequest) returns (stream Update);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
message ExecuteRequest {
|
|
22
|
+
string content_type = 1;
|
|
23
|
+
string data_json = 2;
|
|
24
|
+
string config_json = 3;
|
|
25
|
+
string request_json = 4;
|
|
26
|
+
int32 event = 5;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
message Update {
|
|
30
|
+
oneof payload {
|
|
31
|
+
Progress progress = 1;
|
|
32
|
+
Result result = 2;
|
|
33
|
+
ErrorInfo error = 3;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
message Progress { int32 progress = 1; string message = 2; }
|
|
38
|
+
message Result { string result_json = 1; }
|
|
39
|
+
message ErrorInfo { int32 code = 1; string message = 2; }
|
|
40
|
+
`;
|
|
41
|
+
/**
|
|
42
|
+
* Loads the Agent proto package. proto-loader reads from a file, so the embedded
|
|
43
|
+
* schema is written to a temp path — keeps the package self-contained across the
|
|
44
|
+
* cjs/esm dual build. Returns the loaded package (server uses
|
|
45
|
+
* `.stackfactor.agent.v1.Agent.service`; client uses the `Agent` constructor).
|
|
46
|
+
*/
|
|
47
|
+
export const loadAgentPackage = () => {
|
|
48
|
+
const file = join(tmpdir(), "stackfactor-agent.v1.proto");
|
|
49
|
+
writeFileSync(file, PROTO);
|
|
50
|
+
const packageDefinition = protoLoader.loadSync(file, {
|
|
51
|
+
keepCase: true,
|
|
52
|
+
longs: String,
|
|
53
|
+
enums: String,
|
|
54
|
+
defaults: true,
|
|
55
|
+
oneofs: true,
|
|
56
|
+
});
|
|
57
|
+
return grpc.loadPackageDefinition(packageDefinition);
|
|
58
|
+
};
|
|
59
|
+
/** The Agent gRPC service definition (for the `serve()` server). */
|
|
60
|
+
export const loadAgentService = () => loadAgentPackage().stackfactor.agent.v1.Agent.service;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The fleet `Agent.Execute` request. `*_json` fields are JSON strings.
|
|
3
|
+
* `request_json` MUST include the caller's StackFactor session token as
|
|
4
|
+
* `authToken` — the agent validates it (via `serve()`'s auth gate) before
|
|
5
|
+
* running. This is distinct from the Cloud Run ID token (see `CallAgentOptions`).
|
|
6
|
+
*/
|
|
7
|
+
export interface AgentExecuteRequest {
|
|
8
|
+
content_type: string;
|
|
9
|
+
data_json: string;
|
|
10
|
+
config_json: string;
|
|
11
|
+
request_json: string;
|
|
12
|
+
event: number;
|
|
13
|
+
}
|
|
14
|
+
export interface CallAgentOptions {
|
|
15
|
+
/**
|
|
16
|
+
* Google ID token (audience = the agent's Cloud Run URL) to get past Cloud
|
|
17
|
+
* Run's `--no-allow-unauthenticated` ingress. Attached as `authorization:
|
|
18
|
+
* Bearer` metadata. The agent never sees it; ingress consumes it.
|
|
19
|
+
*/
|
|
20
|
+
idToken?: string;
|
|
21
|
+
/** Called for each streamed `Progress` frame (e.g. to forward to a socket). */
|
|
22
|
+
onProgress?: (update: {
|
|
23
|
+
progress: number;
|
|
24
|
+
message: string;
|
|
25
|
+
}) => void;
|
|
26
|
+
/** Abort the RPC (e.g. the frontend socket dropped) → stops the agent's LLM. */
|
|
27
|
+
signal?: AbortSignal;
|
|
28
|
+
/** Call deadline; defaults to 900s to match Cloud Run's max request timeout. */
|
|
29
|
+
deadlineMs?: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Calls a deployed agent's `Agent.Execute` over gRPC server-streaming. Forwards
|
|
33
|
+
* each `Progress` frame to `onProgress`, resolves with the parsed `result_json`
|
|
34
|
+
* on `Result`, and rejects (with `error.code`) on `ErrorInfo`. Caller-cancel via
|
|
35
|
+
* `options.signal` cancels the RPC.
|
|
36
|
+
*
|
|
37
|
+
* @param agentUrl - The agent's Cloud Run URL (https://…run.app).
|
|
38
|
+
* @param request - The `ExecuteRequest` (its `request_json` carries `authToken`).
|
|
39
|
+
*/
|
|
40
|
+
export declare const callAgent: (agentUrl: string, request: AgentExecuteRequest, options?: CallAgentOptions) => Promise<any>;
|
|
41
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACrE,gFAAgF;IAChF,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,gFAAgF;IAChF,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAqCD;;;;;;;;GAQG;AACH,eAAO,MAAM,SAAS,GACpB,UAAU,MAAM,EAChB,SAAS,mBAAmB,EAC5B,UAAS,gBAAqB,KAC7B,OAAO,CAAC,GAAG,CAyDV,CAAC"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import * as grpc from "@grpc/grpc-js";
|
|
2
|
+
import { loadAgentPackage } from "./agentProto.js";
|
|
3
|
+
const DEFAULT_DEADLINE_MS = 900_000;
|
|
4
|
+
const safeParse = (value, fallback) => {
|
|
5
|
+
if (!value)
|
|
6
|
+
return fallback;
|
|
7
|
+
try {
|
|
8
|
+
return JSON.parse(value);
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return fallback;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
/** Turns an `ErrorInfo` frame into an Error carrying the agent's `code`. */
|
|
15
|
+
const agentError = (frame) => {
|
|
16
|
+
const error = new Error(frame?.message || "Agent error");
|
|
17
|
+
error.code = frame?.code;
|
|
18
|
+
return error;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Channel credentials for an authenticated Cloud Run agent: TLS (Cloud Run
|
|
22
|
+
* terminates at the edge) plus per-call metadata carrying the ID token.
|
|
23
|
+
*/
|
|
24
|
+
const buildCredentials = (idToken) => {
|
|
25
|
+
const ssl = grpc.credentials.createSsl();
|
|
26
|
+
if (!idToken) {
|
|
27
|
+
return ssl;
|
|
28
|
+
}
|
|
29
|
+
const callCreds = grpc.credentials.createFromMetadataGenerator((_ctx, cb) => {
|
|
30
|
+
const metadata = new grpc.Metadata();
|
|
31
|
+
metadata.add("authorization", `Bearer ${idToken}`);
|
|
32
|
+
cb(null, metadata);
|
|
33
|
+
});
|
|
34
|
+
return grpc.credentials.combineChannelCredentials(ssl, callCreds);
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Calls a deployed agent's `Agent.Execute` over gRPC server-streaming. Forwards
|
|
38
|
+
* each `Progress` frame to `onProgress`, resolves with the parsed `result_json`
|
|
39
|
+
* on `Result`, and rejects (with `error.code`) on `ErrorInfo`. Caller-cancel via
|
|
40
|
+
* `options.signal` cancels the RPC.
|
|
41
|
+
*
|
|
42
|
+
* @param agentUrl - The agent's Cloud Run URL (https://…run.app).
|
|
43
|
+
* @param request - The `ExecuteRequest` (its `request_json` carries `authToken`).
|
|
44
|
+
*/
|
|
45
|
+
export const callAgent = (agentUrl, request, options = {}) => new Promise((resolve, reject) => {
|
|
46
|
+
const loaded = loadAgentPackage();
|
|
47
|
+
const url = new URL(agentUrl);
|
|
48
|
+
const address = `${url.hostname}:${url.port || "443"}`;
|
|
49
|
+
const client = new loaded.stackfactor.agent.v1.Agent(address, buildCredentials(options.idToken));
|
|
50
|
+
const stream = client.Execute(request, {
|
|
51
|
+
deadline: Date.now() + (options.deadlineMs ?? DEFAULT_DEADLINE_MS),
|
|
52
|
+
});
|
|
53
|
+
let settled = false;
|
|
54
|
+
const settle = (run) => {
|
|
55
|
+
if (settled) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
settled = true;
|
|
59
|
+
try {
|
|
60
|
+
client.close();
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// ignore close errors
|
|
64
|
+
}
|
|
65
|
+
run();
|
|
66
|
+
};
|
|
67
|
+
if (options.signal) {
|
|
68
|
+
if (options.signal.aborted) {
|
|
69
|
+
stream.cancel();
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
options.signal.addEventListener("abort", () => stream.cancel(), {
|
|
73
|
+
once: true,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
stream.on("data", (update) => {
|
|
78
|
+
if (update.progress) {
|
|
79
|
+
options.onProgress?.({
|
|
80
|
+
progress: update.progress.progress ?? 0,
|
|
81
|
+
message: update.progress.message ?? "",
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
else if (update.result) {
|
|
85
|
+
const result = safeParse(update.result.result_json, null);
|
|
86
|
+
settle(() => resolve(result));
|
|
87
|
+
}
|
|
88
|
+
else if (update.error) {
|
|
89
|
+
settle(() => reject(agentError(update.error)));
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
stream.on("error", (error) => settle(() => reject(error)));
|
|
93
|
+
stream.on("end", () => settle(() => reject(new Error("Agent stream ended without a result or error"))));
|
|
94
|
+
});
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -3,11 +3,14 @@ import errorHandling from "./errorHandling.js";
|
|
|
3
3
|
import langChain from "./langChain.js";
|
|
4
4
|
import logger from "./logger.js";
|
|
5
5
|
import { serve } from "./serve.js";
|
|
6
|
+
import { callAgent } from "./client.js";
|
|
6
7
|
import * as runtimeContext from "./runtimeContext.js";
|
|
7
8
|
export { constants };
|
|
8
9
|
export { errorHandling };
|
|
9
10
|
export { langChain };
|
|
10
11
|
export { logger };
|
|
11
12
|
export { serve };
|
|
13
|
+
export { callAgent };
|
|
14
|
+
export type { AgentExecuteRequest, CallAgentOptions } from "./client.js";
|
|
12
15
|
export { runtimeContext };
|
|
13
16
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/esm/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,YAAY,CAAC;AACnC,OAAO,aAAa,MAAM,oBAAoB,CAAC;AAC/C,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,OAAO,EAAE,aAAa,EAAE,CAAC;AAEzB,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,OAAO,EAAE,MAAM,EAAE,CAAC;AAElB,OAAO,EAAE,KAAK,EAAE,CAAC;AAEjB,OAAO,EAAE,cAAc,EAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,YAAY,CAAC;AACnC,OAAO,aAAa,MAAM,oBAAoB,CAAC;AAC/C,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,OAAO,EAAE,aAAa,EAAE,CAAC;AAEzB,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,OAAO,EAAE,MAAM,EAAE,CAAC;AAElB,OAAO,EAAE,KAAK,EAAE,CAAC;AAEjB,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,YAAY,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEzE,OAAO,EAAE,cAAc,EAAE,CAAC"}
|
package/dist/esm/index.js
CHANGED
|
@@ -3,10 +3,12 @@ import errorHandling from "./errorHandling.js";
|
|
|
3
3
|
import langChain from "./langChain.js";
|
|
4
4
|
import logger from "./logger.js";
|
|
5
5
|
import { serve } from "./serve.js";
|
|
6
|
+
import { callAgent } from "./client.js";
|
|
6
7
|
import * as runtimeContext from "./runtimeContext.js";
|
|
7
8
|
export { constants };
|
|
8
9
|
export { errorHandling };
|
|
9
10
|
export { langChain };
|
|
10
11
|
export { logger };
|
|
11
12
|
export { serve };
|
|
13
|
+
export { callAgent };
|
|
12
14
|
export { runtimeContext };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"langChain.d.ts","sourceRoot":"","sources":["../../src/langChain.ts"],"names":[],"mappings":";0CAiD6C,GAAG,KAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"langChain.d.ts","sourceRoot":"","sources":["../../src/langChain.ts"],"names":[],"mappings":";0CAiD6C,GAAG,KAAG,IAAI;wBAyhB/C,MAAM,aACD,MAAM,gBACH,MAAM,SACb,GAAG,EAAE,kBACI,GAAG,UACX,GAAG,KACV,GAAG;sBAyBG,GAAG,UACF,MAAM,UACN,GAAG,eACC,QAAQ,GAAG,IAAI,KAC1B,OAAO,CAAC,GAAG,CAAC;oCAqXF,MAAM,UACT,GAAG,UACH,GAAG,oBACO,GAAG,eACT,MAAM,eACN,MAAM,wBACG,OAAO,WACpB,GAAG,cACA,MAAM,UACV,GAAG,EAAE,KACX,OAAO,CAAC,GAAG,CAAC;sDAosBF,MAAM,UACT,GAAG,UACH,MAAM,YACL,GAAG,KACX,OAAO,CAAC,GAAG,CAAC;0CAn+B8B,GAAG,KAAG,MAAM;mCAoBxC,MAAM,mBACJ,MAAM,EAAE,KACxB,MAAM;;AAwgCT,wBAQE"}
|
package/dist/esm/langChain.js
CHANGED
|
@@ -63,40 +63,81 @@ const recordCost = (cost) => {
|
|
|
63
63
|
}
|
|
64
64
|
};
|
|
65
65
|
/**
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
66
|
+
* Reads a per-model rate from the flat cost constants the integration defines
|
|
67
|
+
* in its `config.yaml` (exposed on the config object), e.g.
|
|
68
|
+
* `claude-opus-4-7-input-token-costs`. Returns `null` when the constant is
|
|
69
|
+
* absent or not numeric, in which case cost recording becomes a no-op (the
|
|
70
|
+
* call still succeeds — pricing is the integration's configuration concern).
|
|
70
71
|
*/
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
if (!pricing)
|
|
72
|
+
const getModelRate = (modelName, config, kind) => {
|
|
73
|
+
if (!config || !modelName)
|
|
74
74
|
return null;
|
|
75
|
-
|
|
75
|
+
const rate = Number(config[`${modelName}-${kind}-costs`]);
|
|
76
|
+
return Number.isFinite(rate) ? rate : null;
|
|
76
77
|
};
|
|
77
78
|
/**
|
|
78
|
-
*
|
|
79
|
-
*
|
|
79
|
+
* Accumulates the per-model usage breakdown on `global.quota.byModel` so the
|
|
80
|
+
* agent can report input/output token counts and image spend per model to the
|
|
81
|
+
* UI. No-ops when the quota global is absent.
|
|
80
82
|
*/
|
|
81
|
-
const
|
|
83
|
+
const recordModelBreakdown = (modelName, inputCost, outputCost, imageCost, inputTokens = 0, outputTokens = 0) => {
|
|
84
|
+
const quota = globalThis.quota;
|
|
85
|
+
if (!quota || !modelName)
|
|
86
|
+
return;
|
|
87
|
+
if (!quota.byModel || typeof quota.byModel !== "object")
|
|
88
|
+
quota.byModel = {};
|
|
89
|
+
const entry = (quota.byModel[modelName] ||= {
|
|
90
|
+
inputCost: 0,
|
|
91
|
+
outputCost: 0,
|
|
92
|
+
imageCost: 0,
|
|
93
|
+
inputTokens: 0,
|
|
94
|
+
outputTokens: 0,
|
|
95
|
+
});
|
|
96
|
+
// Entries created by older versions of this module lack the token counters.
|
|
97
|
+
if (typeof entry.inputTokens !== "number")
|
|
98
|
+
entry.inputTokens = 0;
|
|
99
|
+
if (typeof entry.outputTokens !== "number")
|
|
100
|
+
entry.outputTokens = 0;
|
|
101
|
+
if (Number.isFinite(inputCost) && inputCost > 0)
|
|
102
|
+
entry.inputCost += inputCost;
|
|
103
|
+
if (Number.isFinite(outputCost) && outputCost > 0)
|
|
104
|
+
entry.outputCost += outputCost;
|
|
105
|
+
if (Number.isFinite(imageCost) && imageCost > 0)
|
|
106
|
+
entry.imageCost += imageCost;
|
|
107
|
+
if (Number.isFinite(inputTokens) && inputTokens > 0)
|
|
108
|
+
entry.inputTokens += inputTokens;
|
|
109
|
+
if (Number.isFinite(outputTokens) && outputTokens > 0)
|
|
110
|
+
entry.outputTokens += outputTokens;
|
|
111
|
+
};
|
|
112
|
+
/**
|
|
113
|
+
* Computes and records the USD cost of a text LLM call from the
|
|
114
|
+
* `<model>-input-token-costs` / `<model>-output-token-costs` constants
|
|
115
|
+
* (dollars per million tokens). Updates both the session total
|
|
116
|
+
* (`quota.usedThisSession` / `quota.remaining`) and the per-model breakdown
|
|
117
|
+
* (`quota.byModel`).
|
|
118
|
+
*/
|
|
119
|
+
const recordTextCost = (modelName, usage, config) => {
|
|
82
120
|
if (!usage)
|
|
83
|
-
return
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const
|
|
88
|
-
const
|
|
89
|
-
|
|
121
|
+
return;
|
|
122
|
+
const inputRate = getModelRate(modelName, config, "input-token") || 0;
|
|
123
|
+
const outputRate = getModelRate(modelName, config, "output-token") || 0;
|
|
124
|
+
const inputTokens = usage.input_tokens || 0;
|
|
125
|
+
const outputTokens = usage.output_tokens || 0;
|
|
126
|
+
const inputCost = (inputTokens / 1_000_000) * inputRate;
|
|
127
|
+
const outputCost = (outputTokens / 1_000_000) * outputRate;
|
|
128
|
+
recordCost(inputCost + outputCost);
|
|
129
|
+
recordModelBreakdown(modelName, inputCost, outputCost, 0, inputTokens, outputTokens);
|
|
90
130
|
};
|
|
91
131
|
/**
|
|
92
|
-
* Computes USD cost
|
|
93
|
-
*
|
|
132
|
+
* Computes and records the USD cost of an image generation call from the
|
|
133
|
+
* `<model>-image-costs` constant (dollars per generated image). Updates both
|
|
134
|
+
* the session total and the per-model breakdown.
|
|
94
135
|
*/
|
|
95
|
-
const
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
136
|
+
const recordImageCost = (modelName, numImages, config) => {
|
|
137
|
+
const rate = getModelRate(modelName, config, "image") || 0;
|
|
138
|
+
const imageCost = (numImages || 0) * rate;
|
|
139
|
+
recordCost(imageCost);
|
|
140
|
+
recordModelBreakdown(modelName, 0, 0, imageCost);
|
|
100
141
|
};
|
|
101
142
|
/**
|
|
102
143
|
* Extracts a normalized token-usage object from a single LangChain `invoke()`
|
|
@@ -564,7 +605,7 @@ const runAgent = async (agent, prompt, config, onProgress = null) => {
|
|
|
564
605
|
throw err;
|
|
565
606
|
}
|
|
566
607
|
}
|
|
567
|
-
|
|
608
|
+
recordTextCost(modelName, sumAgentResponseUsage(response), config);
|
|
568
609
|
const endTime = Date.now();
|
|
569
610
|
const duration = endTime - startTime;
|
|
570
611
|
logger.log(null, logger.levels.info, `Agent "${agent.options?.name}" completed in ${Math.round(duration / 1000)} seconds.`);
|
|
@@ -1039,7 +1080,7 @@ const runPromptWithModel = async (modelName, config, prompt, onProgressReport, m
|
|
|
1039
1080
|
throw err;
|
|
1040
1081
|
}
|
|
1041
1082
|
}
|
|
1042
|
-
|
|
1083
|
+
recordTextCost(modelName, streamUsage, config);
|
|
1043
1084
|
if (!rawContent) {
|
|
1044
1085
|
throw errorHandlingHelper.create(constants.HTTP_CODES.INTERNAL_SERVER_ERROR, "LLM returned no content");
|
|
1045
1086
|
}
|
|
@@ -1139,7 +1180,7 @@ const runPromptWithModel = async (modelName, config, prompt, onProgressReport, m
|
|
|
1139
1180
|
throw err;
|
|
1140
1181
|
}
|
|
1141
1182
|
}
|
|
1142
|
-
|
|
1183
|
+
recordTextCost(modelName, extractUsageFromInvoke(response), config);
|
|
1143
1184
|
const rawContent = response?.content || response;
|
|
1144
1185
|
// If not expecting JSON, return raw content directly
|
|
1145
1186
|
if (!expectsJsonResponse) {
|
|
@@ -1247,7 +1288,7 @@ const generateImageWithOpenAI = async (modelName, config, prompt, options) => {
|
|
|
1247
1288
|
}
|
|
1248
1289
|
assertQuotaAvailable();
|
|
1249
1290
|
const response = await openai.images.generate(requestParams);
|
|
1250
|
-
|
|
1291
|
+
recordImageCost(modelName, response.data?.length || n, config);
|
|
1251
1292
|
// Format response based on number of images
|
|
1252
1293
|
if (n === 1) {
|
|
1253
1294
|
const imageData = response.data[0];
|
|
@@ -1364,7 +1405,7 @@ const generateImageWithGoogle = async (modelName, config, prompt, options) => {
|
|
|
1364
1405
|
if (images.length === 0) {
|
|
1365
1406
|
throw errorHandlingHelper.create(constants.HTTP_CODES.INTERNAL_SERVER_ERROR, `No images were generated by ${modelName}`);
|
|
1366
1407
|
}
|
|
1367
|
-
|
|
1408
|
+
recordImageCost(modelName, images.length, config);
|
|
1368
1409
|
if (numberOfImages === 1 || images.length === 1) {
|
|
1369
1410
|
return images[0];
|
|
1370
1411
|
}
|
package/dist/esm/serve.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/serve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/serve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,eAAe,CAAC;AAMtC;;;;;GAKG;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;AAE/D;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,EAAE,GAAG,KAAK,OAAO,CAAC;IAAE,IAAI,EAAE,GAAG,CAAC;IAAC,MAAM,EAAE,GAAG,CAAA;CAAE,CAAC,CAAC;AAElF,MAAM,WAAW,YAAY;IAC3B,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wFAAwF;IACxF,YAAY,CAAC,EAAE,aAAa,CAAC;CAC9B;AAkDD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,KAAK,GAAI,MAAM,SAAS,EAAE,UAAS,YAAiB,KAAG,IAAI,CAAC,MAsGxE,CAAC"}
|
package/dist/esm/serve.js
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import * as grpc from "@grpc/grpc-js";
|
|
2
|
-
import * as protoLoader from "@grpc/proto-loader";
|
|
3
2
|
import { session as clientSession } from "@stackfactor/client-api";
|
|
4
|
-
import { writeFileSync } from "node:fs";
|
|
5
|
-
import { join } from "node:path";
|
|
6
|
-
import { tmpdir } from "node:os";
|
|
7
3
|
import logger from "./logger.js";
|
|
4
|
+
import { loadAgentService } from "./agentProto.js";
|
|
8
5
|
import { runWithContext, installGlobals } from "./runtimeContext.js";
|
|
9
6
|
/** Marks an auth failure so the handler can map it to gRPC UNAUTHENTICATED. */
|
|
10
7
|
class UnauthenticatedError extends Error {
|
|
@@ -27,55 +24,6 @@ const defaultAuthenticate = async (request) => {
|
|
|
27
24
|
throw new UnauthenticatedError(`Invalid auth token: ${error?.message ?? error}`);
|
|
28
25
|
}
|
|
29
26
|
};
|
|
30
|
-
/**
|
|
31
|
-
* gRPC contract shared by the entire agent fleet. `data`/`config`/`request` are
|
|
32
|
-
* carried as JSON strings so arbitrary payloads need no proto schema churn.
|
|
33
|
-
* `Execute` is server-streaming: zero or more `Progress` frames (driven by the
|
|
34
|
-
* agent's `onProgress`) followed by exactly one `Result` or `Error`.
|
|
35
|
-
*/
|
|
36
|
-
const PROTO = `
|
|
37
|
-
syntax = "proto3";
|
|
38
|
-
package stackfactor.agent.v1;
|
|
39
|
-
|
|
40
|
-
service Agent {
|
|
41
|
-
rpc Execute(ExecuteRequest) returns (stream Update);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
message ExecuteRequest {
|
|
45
|
-
string content_type = 1;
|
|
46
|
-
string data_json = 2;
|
|
47
|
-
string config_json = 3;
|
|
48
|
-
string request_json = 4;
|
|
49
|
-
int32 event = 5;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
message Update {
|
|
53
|
-
oneof payload {
|
|
54
|
-
Progress progress = 1;
|
|
55
|
-
Result result = 2;
|
|
56
|
-
ErrorInfo error = 3;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
message Progress { int32 progress = 1; string message = 2; }
|
|
61
|
-
message Result { string result_json = 1; }
|
|
62
|
-
message ErrorInfo { int32 code = 1; string message = 2; }
|
|
63
|
-
`;
|
|
64
|
-
const loadAgentService = () => {
|
|
65
|
-
// proto-loader reads from a file; write the embedded schema to a temp path so
|
|
66
|
-
// the package stays self-contained across the cjs/esm dual build.
|
|
67
|
-
const file = join(tmpdir(), "stackfactor-agent.v1.proto");
|
|
68
|
-
writeFileSync(file, PROTO);
|
|
69
|
-
const packageDefinition = protoLoader.loadSync(file, {
|
|
70
|
-
keepCase: true,
|
|
71
|
-
longs: String,
|
|
72
|
-
enums: String,
|
|
73
|
-
defaults: true,
|
|
74
|
-
oneofs: true,
|
|
75
|
-
});
|
|
76
|
-
const loaded = grpc.loadPackageDefinition(packageDefinition);
|
|
77
|
-
return loaded.stackfactor.agent.v1.Agent.service;
|
|
78
|
-
};
|
|
79
27
|
const safeParse = (value, fallback) => {
|
|
80
28
|
if (!value)
|
|
81
29
|
return fallback;
|
package/package.json
CHANGED