@granular-software/sdk 0.4.37 → 0.4.38
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/agent-evals.d.mts +16 -3
- package/dist/agent-evals.d.ts +16 -3
- package/dist/agent-evals.js +341 -105
- package/dist/agent-evals.js.map +1 -1
- package/dist/agent-evals.mjs +340 -105
- package/dist/agent-evals.mjs.map +1 -1
- package/dist/cli/index.js +129 -3
- package/dist/client-BNbWA9jQ.d.ts +1064 -0
- package/dist/client-HDJgcJC5.d.mts +1064 -0
- package/dist/index.d.mts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +231 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +225 -4
- package/dist/index.mjs.map +1 -1
- package/dist/spend-rzS1rlFr.d.mts +1559 -0
- package/dist/spend-rzS1rlFr.d.ts +1559 -0
- package/dist/spend.d.mts +2 -0
- package/dist/spend.d.ts +2 -0
- package/dist/spend.js +111 -0
- package/dist/spend.js.map +1 -0
- package/dist/spend.mjs +107 -0
- package/dist/spend.mjs.map +1 -0
- package/package.json +7 -1
- package/dist/client-eE9nTfvp.d.mts +0 -2483
- package/dist/client-eE9nTfvp.d.ts +0 -2483
package/dist/index.mjs
CHANGED
|
@@ -4616,6 +4616,7 @@ function withPromptTranscriptTimeout(promise) {
|
|
|
4616
4616
|
var Session = class {
|
|
4617
4617
|
client;
|
|
4618
4618
|
clientId;
|
|
4619
|
+
initialQuota;
|
|
4619
4620
|
jobsMap = /* @__PURE__ */ new Map();
|
|
4620
4621
|
pendingAgentMessagesByJobId = /* @__PURE__ */ new Map();
|
|
4621
4622
|
eventListeners = /* @__PURE__ */ new Map();
|
|
@@ -4631,9 +4632,10 @@ var Session = class {
|
|
|
4631
4632
|
promptCache = /* @__PURE__ */ new Map();
|
|
4632
4633
|
/** Prompt ids locally answered before the document sync catches up. */
|
|
4633
4634
|
hiddenPromptIds = /* @__PURE__ */ new Set();
|
|
4634
|
-
constructor(client, clientId) {
|
|
4635
|
+
constructor(client, clientId, options = {}) {
|
|
4635
4636
|
this.client = client;
|
|
4636
4637
|
this.clientId = clientId || `client_${Date.now()}`;
|
|
4638
|
+
this.initialQuota = options.initialQuota || null;
|
|
4637
4639
|
this.setupEventHandlers();
|
|
4638
4640
|
this.setupToolInvokeHandler();
|
|
4639
4641
|
}
|
|
@@ -4682,6 +4684,16 @@ var Session = class {
|
|
|
4682
4684
|
get document() {
|
|
4683
4685
|
return this.client.doc;
|
|
4684
4686
|
}
|
|
4687
|
+
get quota() {
|
|
4688
|
+
return this.getQuota();
|
|
4689
|
+
}
|
|
4690
|
+
getQuota() {
|
|
4691
|
+
const quota = this.client.doc.billing?.quota;
|
|
4692
|
+
if (quota && typeof quota === "object") {
|
|
4693
|
+
return quota;
|
|
4694
|
+
}
|
|
4695
|
+
return this.initialQuota;
|
|
4696
|
+
}
|
|
4685
4697
|
get sessionId() {
|
|
4686
4698
|
return this.client.currentSessionId;
|
|
4687
4699
|
}
|
|
@@ -11304,6 +11316,110 @@ async function invokeRegisteredEffect(effectMap, request) {
|
|
|
11304
11316
|
return resolved.handler(request.input, context);
|
|
11305
11317
|
}
|
|
11306
11318
|
|
|
11319
|
+
// src/spend.ts
|
|
11320
|
+
function toGranularHttpBase(apiUrl) {
|
|
11321
|
+
const url = new URL(apiUrl);
|
|
11322
|
+
if (url.protocol === "ws:") {
|
|
11323
|
+
url.protocol = "http:";
|
|
11324
|
+
} else if (url.protocol === "wss:") {
|
|
11325
|
+
url.protocol = "https:";
|
|
11326
|
+
}
|
|
11327
|
+
url.pathname = url.pathname.replace(/\/ws\/connect$/, "").replace(/\/ws$/, "");
|
|
11328
|
+
if (!url.pathname || url.pathname === "/") {
|
|
11329
|
+
url.pathname = "/granular";
|
|
11330
|
+
}
|
|
11331
|
+
url.search = "";
|
|
11332
|
+
url.hash = "";
|
|
11333
|
+
return url.toString().replace(/\/$/, "");
|
|
11334
|
+
}
|
|
11335
|
+
function cleanIdPart(value) {
|
|
11336
|
+
return value.replace(/[^a-zA-Z0-9_-]+/g, "_").replace(/^_+|_+$/g, "");
|
|
11337
|
+
}
|
|
11338
|
+
function buildOpenAISpendEventId(usage, context = {}) {
|
|
11339
|
+
const requestId = usage.requestId?.trim();
|
|
11340
|
+
if (!requestId) return void 0;
|
|
11341
|
+
const scope = context.sessionId || context.environmentId || context.subjectId || context.sandboxId || "global";
|
|
11342
|
+
return ["spend", "openai", scope, requestId].map(cleanIdPart).join("_");
|
|
11343
|
+
}
|
|
11344
|
+
function pricingEffectiveAtSeconds(value) {
|
|
11345
|
+
if (!value) return null;
|
|
11346
|
+
const parsed = Date.parse(value);
|
|
11347
|
+
return Number.isFinite(parsed) ? Math.floor(parsed / 1e3) : null;
|
|
11348
|
+
}
|
|
11349
|
+
function compactContext(context) {
|
|
11350
|
+
return Object.fromEntries(
|
|
11351
|
+
Object.entries(context).filter(
|
|
11352
|
+
([, value]) => value != null && value !== ""
|
|
11353
|
+
)
|
|
11354
|
+
);
|
|
11355
|
+
}
|
|
11356
|
+
function omitTenantId(context) {
|
|
11357
|
+
const scopedContext = { ...context };
|
|
11358
|
+
delete scopedContext.tenantId;
|
|
11359
|
+
return scopedContext;
|
|
11360
|
+
}
|
|
11361
|
+
async function recordOpenAIUsageSpend(options) {
|
|
11362
|
+
const usageContext = compactContext({
|
|
11363
|
+
...options.usage.usageContext || {},
|
|
11364
|
+
...options.context || {}
|
|
11365
|
+
});
|
|
11366
|
+
const context = omitTenantId(usageContext);
|
|
11367
|
+
const spendEventId = options.usage.spendEventId || buildOpenAISpendEventId(options.usage, context);
|
|
11368
|
+
const metadata = {
|
|
11369
|
+
...options.metadata || {},
|
|
11370
|
+
...options.usage.rawUsage !== void 0 ? { openaiUsage: options.usage.rawUsage } : {},
|
|
11371
|
+
usageContext: context
|
|
11372
|
+
};
|
|
11373
|
+
const response = await fetch(
|
|
11374
|
+
`${toGranularHttpBase(options.apiUrl)}/control/spend/events`,
|
|
11375
|
+
{
|
|
11376
|
+
method: "POST",
|
|
11377
|
+
cache: "no-store",
|
|
11378
|
+
headers: {
|
|
11379
|
+
Authorization: `Bearer ${options.token}`,
|
|
11380
|
+
"Content-Type": "application/json"
|
|
11381
|
+
},
|
|
11382
|
+
body: JSON.stringify({
|
|
11383
|
+
...spendEventId ? { spendEventId } : {},
|
|
11384
|
+
sandboxId: context.sandboxId || null,
|
|
11385
|
+
environmentId: context.environmentId || null,
|
|
11386
|
+
sessionId: context.sessionId || null,
|
|
11387
|
+
subjectId: context.subjectId || null,
|
|
11388
|
+
permissionProfileId: context.permissionProfileId || null,
|
|
11389
|
+
source: "openai",
|
|
11390
|
+
lineItemType: "llm_tokens",
|
|
11391
|
+
provider: options.usage.provider,
|
|
11392
|
+
model: options.usage.model,
|
|
11393
|
+
operation: options.usage.operation || "chat.completions",
|
|
11394
|
+
requestId: options.usage.requestId || null,
|
|
11395
|
+
inputTokens: options.usage.inputTokens,
|
|
11396
|
+
outputTokens: options.usage.outputTokens,
|
|
11397
|
+
cachedInputTokens: options.usage.cachedInputTokens,
|
|
11398
|
+
reasoningTokens: options.usage.reasoningTokens,
|
|
11399
|
+
quantity: options.usage.totalTokens,
|
|
11400
|
+
quantityUnit: "tokens",
|
|
11401
|
+
inputPricePerMillionMicros: options.usage.inputPricePerMillionMicros,
|
|
11402
|
+
cachedInputPricePerMillionMicros: options.usage.cachedInputPricePerMillionMicros,
|
|
11403
|
+
outputPricePerMillionMicros: options.usage.outputPricePerMillionMicros,
|
|
11404
|
+
amountMicros: options.usage.amountMicros,
|
|
11405
|
+
currency: options.usage.currency,
|
|
11406
|
+
pricingSource: options.usage.pricingSource,
|
|
11407
|
+
pricingEffectiveAt: pricingEffectiveAtSeconds(
|
|
11408
|
+
options.usage.pricingEffectiveAt
|
|
11409
|
+
),
|
|
11410
|
+
estimated: false,
|
|
11411
|
+
metadata
|
|
11412
|
+
})
|
|
11413
|
+
}
|
|
11414
|
+
);
|
|
11415
|
+
if (!response.ok) {
|
|
11416
|
+
throw new Error(
|
|
11417
|
+
`Granular spend event failed (${response.status}): ${await response.text()}`
|
|
11418
|
+
);
|
|
11419
|
+
}
|
|
11420
|
+
return response.json();
|
|
11421
|
+
}
|
|
11422
|
+
|
|
11307
11423
|
// ../metamodel-enum/src/index.ts
|
|
11308
11424
|
function renderInlineStringUnion(values) {
|
|
11309
11425
|
return values.map((value) => JSON.stringify(value)).join(" | ");
|
|
@@ -14086,7 +14202,7 @@ var EnvironmentSession = class extends Session {
|
|
|
14086
14202
|
/** The last known graph container status, updated by checkReadiness() or on heartbeat */
|
|
14087
14203
|
graphContainerStatus = null;
|
|
14088
14204
|
constructor(client, environment, clientId, options = {}) {
|
|
14089
|
-
super(client, clientId);
|
|
14205
|
+
super(client, clientId, { initialQuota: options.initialQuota });
|
|
14090
14206
|
this.environment = environment;
|
|
14091
14207
|
this.sessionDataRoutePrefix = options.sessionDataRoutePrefix || "/orchestrator/ws/sessions";
|
|
14092
14208
|
}
|
|
@@ -14885,6 +15001,15 @@ var Granular = class _Granular {
|
|
|
14885
15001
|
const environment = this.bindEnvironmentHandle(envData);
|
|
14886
15002
|
return this.bindWebSocketEnvironmentSession(environment, clientId, minted);
|
|
14887
15003
|
}
|
|
15004
|
+
async recordOpenAIUsageSpend(usage, context, options) {
|
|
15005
|
+
return recordOpenAIUsageSpend({
|
|
15006
|
+
apiUrl: this.apiUrl,
|
|
15007
|
+
token: this.apiKey,
|
|
15008
|
+
usage,
|
|
15009
|
+
context,
|
|
15010
|
+
metadata: options?.metadata
|
|
15011
|
+
});
|
|
15012
|
+
}
|
|
14888
15013
|
/**
|
|
14889
15014
|
* Mark a session closed in the control plane. If `environment` is the connected handle for that
|
|
14890
15015
|
* `sessionId`, disconnects the WebSocket so the runtime tears down cleanly.
|
|
@@ -15039,7 +15164,8 @@ var Granular = class _Granular {
|
|
|
15039
15164
|
const environmentSession = new EnvironmentSession(
|
|
15040
15165
|
client,
|
|
15041
15166
|
environment,
|
|
15042
|
-
clientId
|
|
15167
|
+
clientId,
|
|
15168
|
+
{ initialQuota: session.quota || null }
|
|
15043
15169
|
);
|
|
15044
15170
|
await environmentSession.hello();
|
|
15045
15171
|
return environmentSession;
|
|
@@ -17578,6 +17704,101 @@ ${knownFactsBlock}
|
|
|
17578
17704
|
${input.request?.trim() || "Use the latest user message in the conversation."}`;
|
|
17579
17705
|
}
|
|
17580
17706
|
|
|
17581
|
-
|
|
17707
|
+
// src/openai-usage.ts
|
|
17708
|
+
var OPENAI_PRICING_SOURCE_URL = "https://developers.openai.com/api/docs/models/gpt-5.4/";
|
|
17709
|
+
var OPENAI_PRICING_EFFECTIVE_DATE = "2026-05-19";
|
|
17710
|
+
var OPENAI_MODEL_PRICING_USD_PER_MILLION = {
|
|
17711
|
+
"gpt-5.4": {
|
|
17712
|
+
provider: "openai",
|
|
17713
|
+
model: "gpt-5.4",
|
|
17714
|
+
currency: "USD",
|
|
17715
|
+
inputUsdPerMillion: 2.5,
|
|
17716
|
+
cachedInputUsdPerMillion: 0.25,
|
|
17717
|
+
outputUsdPerMillion: 15,
|
|
17718
|
+
sourceUrl: OPENAI_PRICING_SOURCE_URL,
|
|
17719
|
+
effectiveDate: OPENAI_PRICING_EFFECTIVE_DATE
|
|
17720
|
+
}
|
|
17721
|
+
};
|
|
17722
|
+
function asRecord5(value) {
|
|
17723
|
+
return value && typeof value === "object" ? value : null;
|
|
17724
|
+
}
|
|
17725
|
+
function numberField(record, key) {
|
|
17726
|
+
const value = record?.[key];
|
|
17727
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
17728
|
+
}
|
|
17729
|
+
function microsPerMillion(usdPerMillion) {
|
|
17730
|
+
return Math.round(usdPerMillion * 1e6);
|
|
17731
|
+
}
|
|
17732
|
+
function getOpenAIModelPricing(model) {
|
|
17733
|
+
return OPENAI_MODEL_PRICING_USD_PER_MILLION[model] || null;
|
|
17734
|
+
}
|
|
17735
|
+
function normalizeOpenAIUsage(rawUsage) {
|
|
17736
|
+
const usage = asRecord5(rawUsage);
|
|
17737
|
+
if (!usage) {
|
|
17738
|
+
return {
|
|
17739
|
+
inputTokens: 0,
|
|
17740
|
+
cachedInputTokens: 0,
|
|
17741
|
+
uncachedInputTokens: 0,
|
|
17742
|
+
outputTokens: 0,
|
|
17743
|
+
reasoningTokens: 0,
|
|
17744
|
+
totalTokens: 0
|
|
17745
|
+
};
|
|
17746
|
+
}
|
|
17747
|
+
const inputTokens = numberField(usage, "prompt_tokens") || numberField(usage, "input_tokens");
|
|
17748
|
+
const outputTokens = numberField(usage, "completion_tokens") || numberField(usage, "output_tokens");
|
|
17749
|
+
const totalTokens = numberField(usage, "total_tokens") || inputTokens + outputTokens;
|
|
17750
|
+
const inputDetails = asRecord5(usage.prompt_tokens_details) || asRecord5(usage.input_tokens_details);
|
|
17751
|
+
const outputDetails = asRecord5(usage.completion_tokens_details) || asRecord5(usage.output_tokens_details);
|
|
17752
|
+
const cachedInputTokens = Math.min(
|
|
17753
|
+
inputTokens,
|
|
17754
|
+
numberField(inputDetails, "cached_tokens") || numberField(inputDetails, "cached_input_tokens")
|
|
17755
|
+
);
|
|
17756
|
+
const reasoningTokens = numberField(outputDetails, "reasoning_tokens") || numberField(outputDetails, "reasoning_output_tokens");
|
|
17757
|
+
return {
|
|
17758
|
+
inputTokens,
|
|
17759
|
+
cachedInputTokens,
|
|
17760
|
+
uncachedInputTokens: Math.max(inputTokens - cachedInputTokens, 0),
|
|
17761
|
+
outputTokens,
|
|
17762
|
+
reasoningTokens,
|
|
17763
|
+
totalTokens
|
|
17764
|
+
};
|
|
17765
|
+
}
|
|
17766
|
+
function calculateOpenAITokenSpend(model, rawUsage) {
|
|
17767
|
+
const pricing = getOpenAIModelPricing(model);
|
|
17768
|
+
if (!pricing) return null;
|
|
17769
|
+
const usage = normalizeOpenAIUsage(rawUsage);
|
|
17770
|
+
const inputPricePerMillionMicros = microsPerMillion(
|
|
17771
|
+
pricing.inputUsdPerMillion
|
|
17772
|
+
);
|
|
17773
|
+
const cachedInputPricePerMillionMicros = microsPerMillion(
|
|
17774
|
+
pricing.cachedInputUsdPerMillion
|
|
17775
|
+
);
|
|
17776
|
+
const outputPricePerMillionMicros = microsPerMillion(
|
|
17777
|
+
pricing.outputUsdPerMillion
|
|
17778
|
+
);
|
|
17779
|
+
const amountMicros = Math.round(
|
|
17780
|
+
(usage.uncachedInputTokens * inputPricePerMillionMicros + usage.cachedInputTokens * cachedInputPricePerMillionMicros + usage.outputTokens * outputPricePerMillionMicros) / 1e6
|
|
17781
|
+
);
|
|
17782
|
+
return {
|
|
17783
|
+
provider: "openai",
|
|
17784
|
+
model,
|
|
17785
|
+
inputTokens: usage.inputTokens,
|
|
17786
|
+
cachedInputTokens: usage.cachedInputTokens,
|
|
17787
|
+
uncachedInputTokens: usage.uncachedInputTokens,
|
|
17788
|
+
outputTokens: usage.outputTokens,
|
|
17789
|
+
reasoningTokens: usage.reasoningTokens,
|
|
17790
|
+
totalTokens: usage.totalTokens,
|
|
17791
|
+
amountMicros,
|
|
17792
|
+
currency: "USD",
|
|
17793
|
+
inputPricePerMillionMicros,
|
|
17794
|
+
cachedInputPricePerMillionMicros,
|
|
17795
|
+
outputPricePerMillionMicros,
|
|
17796
|
+
pricingSource: pricing.sourceUrl,
|
|
17797
|
+
pricingEffectiveAt: pricing.effectiveDate,
|
|
17798
|
+
usage
|
|
17799
|
+
};
|
|
17800
|
+
}
|
|
17801
|
+
|
|
17802
|
+
export { Environment, EnvironmentSession, Granular, OPENAI_MODEL_PRICING_USD_PER_MILLION, OntologyHandle, Session, WSClient, buildContinuationInstruction, buildGranularAgentCheckpointBlock, buildGranularAgentDomainBlock, buildGranularAgentHeapBlock, buildGranularAgentLoopBlock, buildGranularAgentReferentBlock, buildGranularAgentSessionBlock, buildGranularAgentSystemPrompt, buildGranularAgentToolBlock, buildGranularAgentWorkflowBlock, buildOpenAISpendEventId, buildSessionTranscript, calculateOpenAITokenSpend, consumeGranularReasoningOnlyChunk, consumeGranularReasoningTraceChunk, createHarnessVerifierSnapshot, evaluateContinuation, extractPromptTokens, getCurrentClosureId, getExclusivePromptTarget, getOpenAIModelPricing, hasOpenPrompt, invokeRegisteredEffect, isLocalApiUrl, normalizeEffectBehaviors, normalizeOpenAIUsage, normalizePrompt, normalizePromptChoiceOption, normalizePromptText, normalizePromptType, projectConversationReferentFocus, projectConversationReferentSummary, projectHeapSummary, projectLoopSummary, projectWorkflowFocus, projectWorkflowSummary, recordOpenAIUsageSpend, resolveApiUrl, resolveAuthTokenForApiUrl, resolveJobPresentation, resolvePromptAnswer, reviewGeneratedJobCode, scorePromptChoiceMatch, stripGranularReasoningTrace, toGranularHttpBase };
|
|
17582
17803
|
//# sourceMappingURL=index.mjs.map
|
|
17583
17804
|
//# sourceMappingURL=index.mjs.map
|