@north-light/cli 0.3.551 → 0.3.553
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/api/client.d.ts +11 -0
- package/dist/api/client.js +3 -3
- package/dist/api/contract.d.ts +1 -1
- package/dist/api/contract.js +1 -1
- package/dist/api/dto/charges.d.ts +122 -0
- package/dist/api/dto/charges.js +0 -0
- package/dist/api/dto/usage.d.ts +3 -3
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.js +1 -1
- package/dist/api/routes.d.ts +3 -0
- package/dist/api/routes.js +1 -1
- package/dist/builtin-memory/crouter-sdk/release-notes.md +10 -0
- package/dist/clients/attach/viewer.js +50 -50
- package/dist/commands/sys/spend.d.ts +1 -0
- package/dist/commands/sys/spend.js +3 -0
- package/dist/commands/sys.js +1 -1
- package/dist/core/canvas/canvas.js +4 -4
- package/dist/core/canvas/db.js +4 -4
- package/dist/core/canvas/export-sqlite.js +2 -2
- package/dist/core/canvas/import-sqlite.d.ts +2 -0
- package/dist/core/canvas/import-sqlite.js +4 -4
- package/dist/core/canvas/person.js +7 -16
- package/dist/core/canvas/schema-chain.d.ts +34 -0
- package/dist/core/canvas/schema-chain.js +1 -0
- package/dist/core/canvas/schema-pg/.gitkeep +0 -0
- package/dist/core/canvas/schema-pg.sql +61 -0
- package/dist/core/canvas/schema-version.d.ts +29 -3
- package/dist/core/canvas/schema-version.js +1 -1
- package/dist/core/canvas/types.d.ts +4 -0
- package/dist/core/config.js +1 -1
- package/dist/core/grants/mirror.d.ts +2 -1
- package/dist/core/grants/mirror.js +2 -2
- package/dist/core/ledger/backfill.d.ts +12 -0
- package/dist/core/ledger/backfill.js +22 -0
- package/dist/core/ledger/charges.d.ts +18 -0
- package/dist/core/ledger/charges.js +1 -0
- package/dist/core/ledger/check.d.ts +44 -0
- package/dist/core/ledger/check.js +7 -0
- package/dist/core/ledger/index.d.ts +9 -0
- package/dist/core/ledger/index.js +1 -0
- package/dist/core/ledger/limits.d.ts +15 -0
- package/dist/core/ledger/limits.js +3 -0
- package/dist/core/ledger/months.d.ts +6 -0
- package/dist/core/ledger/months.js +1 -0
- package/dist/core/ledger/payer.d.ts +34 -0
- package/dist/core/ledger/payer.js +1 -0
- package/dist/core/ledger/read.d.ts +44 -0
- package/dist/core/ledger/read.js +3 -0
- package/dist/core/ledger/totals.d.ts +19 -0
- package/dist/core/ledger/totals.js +4 -0
- package/dist/core/ledger/types.d.ts +66 -0
- package/dist/core/ledger/types.js +0 -0
- package/dist/core/llm/run.d.ts +17 -5
- package/dist/core/llm/run.js +2 -2
- package/dist/core/providers/call.d.ts +7 -1
- package/dist/core/providers/call.js +1 -1
- package/dist/core/providers/errors.js +1 -1
- package/dist/core/providers/receipts.d.ts +7 -1
- package/dist/core/providers/receipts.js +1 -3
- package/dist/core/runs/operations.d.ts +1 -0
- package/dist/core/runs/operations.js +7 -7
- package/dist/core/runtime/broker/cli-relay.js +1 -1
- package/dist/core/runtime/broker/model-adapter.js +2 -2
- package/dist/core/runtime/broker/turn-cause.d.ts +7 -0
- package/dist/core/runtime/broker/turn-cause.js +1 -0
- package/dist/core/runtime/broker.js +1 -1
- package/dist/core/runtime/nodes.d.ts +2 -0
- package/dist/core/runtime/nodes.js +1 -1
- package/dist/core/runtime/recycle.js +1 -1
- package/dist/core/runtime/reset.js +1 -1
- package/dist/core/runtime/revive.js +2 -2
- package/dist/core/runtime/spawn.d.ts +2 -0
- package/dist/core/runtime/spawn.js +2 -2
- package/dist/core/runtime/start-check.d.ts +15 -0
- package/dist/core/runtime/start-check.js +1 -0
- package/dist/core/runtime/warm-pool.js +1 -1
- package/dist/core/user-settings.d.ts +4 -0
- package/dist/core/user-settings.js +1 -1
- package/dist/daemon/api/app-listener.js +13 -13
- package/dist/daemon/api/handlers/bash-jobs.js +1 -1
- package/dist/daemon/api/handlers/charges.d.ts +3 -0
- package/dist/daemon/api/handlers/charges.js +1 -0
- package/dist/daemon/api/handlers/llm.d.ts +9 -5
- package/dist/daemon/api/handlers/llm.js +3 -3
- package/dist/daemon/api/handlers/messages.js +2 -2
- package/dist/daemon/api/handlers/providers.d.ts +2 -0
- package/dist/daemon/api/handlers/providers.js +1 -1
- package/dist/daemon/api/handlers/run-routes.js +1 -1
- package/dist/daemon/api/handlers/runs.d.ts +1 -1
- package/dist/daemon/api/handlers/runs.js +1 -1
- package/dist/daemon/api/operations.js +1 -1
- package/dist/daemon/api/router.d.ts +8 -0
- package/dist/daemon/api/router.js +1 -1
- package/dist/daemon/api/server.js +1 -1
- package/dist/daemon/cron/authority.d.ts +1 -1
- package/dist/daemon/cron-run.js +2 -2
- package/dist/daemon/crtrd.js +10 -10
- package/dist/daemon/fleet.js +4 -4
- package/dist/daemon/reconcilers/action-lane.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.d.ts +2 -0
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +1 -1
- package/dist/types.d.ts +4 -0
- package/docs/sdk/release-notes.md +10 -0
- package/package.json +3 -2
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +13 -13
- package/scripts/install-runtime.mjs +6 -20
- package/scripts/lib/canvas-schema-gate.mjs +20 -0
- package/dist/core/usage/ledger.d.ts +0 -49
- package/dist/core/usage/ledger.js +0 -10
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
var _=Object.defineProperty;var a=(e,n)=>_(e,"name",{value:n,configurable:!0});import{openDb as f}from"../canvas/db.js";import{RunError as h}from"../runs/operations.js";import{chargeOf as g}from"./charges.js";import{listLimits as E}from"./limits.js";import{resetAt as y,usageMonth as l}from"./months.js";const N="id, request, at, month, kind, what, units, usd, payer, funding, sub, grantee, node, run, provider, caused_by, vendor_ref, refused";async function v(e,n=l()){const t=await f(),s=await t.prepare(`SELECT payer, what, kind, units, usd FROM charges
|
|
2
|
+
WHERE grantee = ? AND month = ? AND refused IS NULL AND kind <> 'take'`).all(e,n),o=a(u=>{const p=new Map;for(const r of s){if(r.kind!=="model"||!r.payer.startsWith(u))continue;const m=r.units===null?{}:JSON.parse(r.units),c=p.get(r.what)??{served_model:r.what,input_tokens:0,output_tokens:0,usd_equivalent:null};c.input_tokens+=m.input??0,c.output_tokens+=m.output??0,r.usd!==null&&(c.usd_equivalent=(c.usd_equivalent??0)+Number(r.usd)),p.set(r.what,c)}return[...p.values()].sort((r,m)=>r.served_model<m.served_model?-1:1)},"byModel"),i=a(u=>s.filter(p=>p.payer.startsWith(u)).reduce((p,r)=>p+Number(r.usd??0),0),"sum"),d=await t.prepare("SELECT usd_per_month FROM limits WHERE source = 'grant_sync' AND grantee = ? AND payer LIKE 'user:%' AND funding IS NULL AND provider IS NULL ORDER BY id LIMIT 1").get(e);return{grantee:e,month:n,usd_equivalent:i("user:"),by_model:o("user:"),app_paid:{usd_equivalent:i("app:"),by_model:o("app:")},spend_cap:d===void 0?null:Number(d.usd_per_month),reset_at:y(n)}}a(v,"usageFor");const R=/^(message|request|cron_run|run):(.+)$/;function b(e){const n=R.exec(e);if(n===null)return{sql:"id = ?",params:[e]};if(n[1]==="message"||n[1]==="cron_run")return{sql:"caused_by = ?",params:[e]};if(n[1]==="request")return{sql:"(request = ? OR caused_by = ?)",params:[n[2],e]};const t=n[2];return{sql:`(run = ? OR run IN (SELECT n.run_id FROM nodes n WHERE n.run_id IS NOT NULL AND n.node_id = n.run_id AND n.caused_by IN (
|
|
3
|
+
SELECT 'request:' || c.request FROM charges c WHERE c.run = ? AND c.request IS NOT NULL)))`,params:[t,t]}}a(b,"referenceCondition");const L=a(e=>Buffer.from(JSON.stringify([e.at,e.id]),"utf8").toString("base64url"),"encodeCursor");function O(e){try{const n=JSON.parse(Buffer.from(e,"base64url").toString("utf8"));if(Array.isArray(n)&&n.length===2&&typeof n[0]=="string"&&typeof n[1]=="string")return[n[0],n[1]]}catch{}throw new h(400,"invalid_request","cursor must be a `next` value from a previous page","after")}a(O,"decodeCursor");async function C(e={}){const n=Math.min(Math.max(Math.trunc(e.limit??1e3),1),1e4),t=[],s=[];if(e.under!==void 0){const d=b(e.under);t.push(d.sql),s.push(...d.params),e.month!==void 0&&(t.push("month = ?"),s.push(e.month))}else t.push("month = ?"),s.push(e.month??l());e.grantee!==void 0&&(t.push("grantee = ?"),s.push(e.grantee)),e.after!==void 0&&(t.push("(at, id) > (?, ?)"),s.push(...O(e.after)));const o=(await(await f()).prepare(`SELECT ${N} FROM charges WHERE ${t.join(" AND ")} ORDER BY at, id LIMIT ${n+1}`).all(...s)).map(g),i=o.slice(0,n);return{charges:i,next:o.length>n?L(i[n-1]):null}}a(C,"listCharges");async function I(e=l(),n){const t=await f(),s=n===void 0?"":" AND payer = ?",o=n===void 0?[e]:[e,n],i=await t.prepare(`SELECT payer, SUM(usd) AS usd FROM charge_totals WHERE month = ?${s} GROUP BY payer ORDER BY payer`).all(...o),d=await t.prepare(`SELECT payer, funding, SUM(usd) AS usd FROM charge_totals WHERE month = ?${s} GROUP BY payer, funding ORDER BY payer, funding`).all(...o);return{month:e,by_payer:i.map(u=>({payer:u.payer,usd:Number(u.usd)})),by_funding:d.map(u=>({payer:u.payer,funding:u.funding,usd:Number(u.usd)})),limits:await E(n===void 0?{}:{payer:n})}}a(I,"monthTotals");function T(e){if(e.length===0||e.length>512)throw new h(400,"invalid_request","under must be a reference or a charge id","under");return e}a(T,"assertReference");export{T as assertReference,C as listCharges,I as monthTotals,v as usageFor};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { CanvasDb } from '../canvas/db.js';
|
|
2
|
+
/** `charge_totals` stores an absent `sub` or `provider` as ''. */
|
|
3
|
+
export declare const absent: (value: string | null | undefined) => string;
|
|
4
|
+
/** Add `usd` (null adds 0) to the rollup row of one charge, in the caller's transaction. Concurrent writers to one key
|
|
5
|
+
* serialize on the conflicting row, so the total is exact. */
|
|
6
|
+
export declare function addToTotals(db: CanvasDb, charge: {
|
|
7
|
+
month: string;
|
|
8
|
+
payer: string;
|
|
9
|
+
funding: string;
|
|
10
|
+
sub: string | null;
|
|
11
|
+
grantee: string;
|
|
12
|
+
provider: string | null;
|
|
13
|
+
usd: number | null;
|
|
14
|
+
}): Promise<void>;
|
|
15
|
+
/** Rebuild the whole rollup from `charges`. */
|
|
16
|
+
export declare function rebuildTotals(db: CanvasDb): Promise<void>;
|
|
17
|
+
/** Delete the rollup rows that name `a` or `b` as payer, sub or grantee and rebuild them from `charges`, so two rows that
|
|
18
|
+
* now share a key are summed once. For person substitution, in the same transaction as the rename. */
|
|
19
|
+
export declare function rebuildTotalsFor(db: CanvasDb, a: string, b: string): Promise<void>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
var s=Object.defineProperty;var t=(r,e)=>s(r,"name",{value:e,configurable:!0});const a=t(r=>r??"","absent");async function p(r,e){await r.prepare(`INSERT INTO charge_totals (month, payer, funding, sub, grantee, provider, usd) VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
2
|
+
ON CONFLICT (month, payer, funding, sub, grantee, provider) DO UPDATE SET usd = charge_totals.usd + excluded.usd`).run(e.month,e.payer,e.funding,a(e.sub),e.grantee,a(e.provider),e.usd??0)}t(p,"addToTotals");const u=`SELECT month, payer, funding, COALESCE(sub, ''), grantee, COALESCE(provider, ''), COALESCE(SUM(usd), 0)
|
|
3
|
+
FROM charges WHERE refused IS NULL AND kind <> 'take'`,o="GROUP BY month, payer, funding, COALESCE(sub, ''), grantee, COALESCE(provider, '')";async function d(r){await r.prepare("DELETE FROM charge_totals").run(),await r.prepare(`INSERT INTO charge_totals (month, payer, funding, sub, grantee, provider, usd) ${u} ${o}`).run()}t(d,"rebuildTotals");async function i(r,e,n){await r.prepare("DELETE FROM charge_totals WHERE payer IN (?, ?) OR sub IN (?, ?) OR grantee IN (?, ?)").run(e,n,e,n,e,n),await r.prepare(`INSERT INTO charge_totals (month, payer, funding, sub, grantee, provider, usd) ${u}
|
|
4
|
+
AND (payer IN (?, ?) OR sub IN (?, ?) OR grantee IN (?, ?)) ${o}`).run(e,n,e,n,e,n)}t(i,"rebuildTotalsFor");export{a as absent,p as addToTotals,d as rebuildTotals,i as rebuildTotalsFor};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export type ChargeKind = 'model' | 'tool' | 'sandbox' | 'job' | 'storage' | 'take';
|
|
2
|
+
export type Funding = 'bill' | 'subscription' | 'key' | 'endpoint' | 'take' | 'legacy';
|
|
3
|
+
export type LimitSource = 'grant_sync' | 'person' | 'operator';
|
|
4
|
+
/** Why the check refused a call: the limit's id and a sentence. Stored on the refused row. */
|
|
5
|
+
export interface RefusedMark {
|
|
6
|
+
limit: string;
|
|
7
|
+
reason: string;
|
|
8
|
+
}
|
|
9
|
+
/** One `charges` row as stored. */
|
|
10
|
+
export interface Charge {
|
|
11
|
+
id: string;
|
|
12
|
+
request: string | null;
|
|
13
|
+
at: string;
|
|
14
|
+
month: string;
|
|
15
|
+
kind: ChargeKind;
|
|
16
|
+
what: string;
|
|
17
|
+
/** `{input, output, cache_read, cache_write}` tokens, or `{units, unit}` from a receipt; null on a legacy tool row. */
|
|
18
|
+
units: Record<string, unknown> | null;
|
|
19
|
+
usd: number | null;
|
|
20
|
+
payer: string;
|
|
21
|
+
funding: Funding;
|
|
22
|
+
sub: string | null;
|
|
23
|
+
grantee: string;
|
|
24
|
+
node: string | null;
|
|
25
|
+
run: string | null;
|
|
26
|
+
provider: string | null;
|
|
27
|
+
caused_by: string | null;
|
|
28
|
+
vendor_ref: string | null;
|
|
29
|
+
refused: RefusedMark | null;
|
|
30
|
+
}
|
|
31
|
+
/** What a site hands `writeCharge`. */
|
|
32
|
+
export interface ChargeInput {
|
|
33
|
+
/** `receipt:<provider>:<receipt_id>` for a tool charge; a fresh id when absent. A repeat of an existing id adds nothing. */
|
|
34
|
+
id?: string;
|
|
35
|
+
request?: string | null;
|
|
36
|
+
at?: Date;
|
|
37
|
+
kind: ChargeKind;
|
|
38
|
+
what: string;
|
|
39
|
+
units?: Record<string, unknown> | null;
|
|
40
|
+
/** The list-price amount; null when the model has no list price. Ignored (0 is stored) when `refused` is set. */
|
|
41
|
+
usd: number | null;
|
|
42
|
+
payer: string;
|
|
43
|
+
funding: Funding;
|
|
44
|
+
sub?: string | null;
|
|
45
|
+
grantee: string;
|
|
46
|
+
node?: string | null;
|
|
47
|
+
run?: string | null;
|
|
48
|
+
provider?: string | null;
|
|
49
|
+
causedBy?: string | null;
|
|
50
|
+
vendorRef?: string | null;
|
|
51
|
+
/** Set when the check refused this call: the row is stored with usd 0 and is not added to the rollup. */
|
|
52
|
+
refused?: RefusedMark | null;
|
|
53
|
+
}
|
|
54
|
+
/** One `limits` row. A null filter means any. */
|
|
55
|
+
export interface Limit {
|
|
56
|
+
id: string;
|
|
57
|
+
payer: string;
|
|
58
|
+
funding: Funding | null;
|
|
59
|
+
grantee: string | null;
|
|
60
|
+
provider: string | null;
|
|
61
|
+
sub: string | null;
|
|
62
|
+
usd_per_month: number;
|
|
63
|
+
source: LimitSource;
|
|
64
|
+
updated_at: string;
|
|
65
|
+
}
|
|
66
|
+
export type LimitInput = Omit<Limit, 'updated_at' | 'funding' | 'grantee' | 'provider' | 'sub'> & Partial<Pick<Limit, 'funding' | 'grantee' | 'provider' | 'sub'>>;
|
|
File without changes
|
package/dist/core/llm/run.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { type ThinkingLevel } from '@earendil-works/pi-ai/compat';
|
|
2
|
-
import { type SpendTarget } from '../usage/ledger.js';
|
|
3
2
|
import type { GrantRecord, InferenceEndpoint } from '../grants/mirror.js';
|
|
4
3
|
type WireContent = string | null | Array<{
|
|
5
4
|
type: 'text';
|
|
@@ -63,11 +62,24 @@ export interface LlmCaller {
|
|
|
63
62
|
inference_endpoint: InferenceEndpoint | null;
|
|
64
63
|
}
|
|
65
64
|
export declare function llmCallerOf(grant: Pick<GrantRecord, 'payer' | 'sub' | 'grantee' | 'inference_endpoint'> | null | undefined): LlmCaller | undefined;
|
|
66
|
-
/**
|
|
67
|
-
* `
|
|
68
|
-
* is
|
|
65
|
+
/** Who a call is attributed to in the ledger. `grantee` is the app the charge belongs to (`app:terminal` for the person's own agent);
|
|
66
|
+
* `sub` the person the work is for (the runtime's person when absent); `node` and `run` place the row under its run;
|
|
67
|
+
* `request` is the `/v1/llm` `Request-Id` stored on the row (the completion id when absent).
|
|
68
|
+
* `spend_cap` is ignored: limits are `limits` rows the ledger check reads; a caller still passing it is L5's to drop. */
|
|
69
|
+
export interface LlmSpend {
|
|
70
|
+
grantee: string;
|
|
71
|
+
sub?: string | null;
|
|
72
|
+
node?: string | null;
|
|
73
|
+
run?: string | null;
|
|
74
|
+
request?: string;
|
|
75
|
+
spend_cap?: number | null;
|
|
76
|
+
}
|
|
77
|
+
/** `spend`: who the call is attributed to. With it, the ledger check runs for each candidate route before its vendor request
|
|
78
|
+
* (a refused route writes a refused row and the next candidate is tried; all refused is `cap_exhausted` with the first refusal)
|
|
79
|
+
* and a completed call writes one `charges` row. Omitted, the call is neither checked nor recorded.
|
|
80
|
+
* `causedBy`: the request's `Crtr-Caused-By` value (`message:<id>`, `request:<id>`, `cron_run:<id>`), when it carried one; stored on the row. */
|
|
69
81
|
export declare function runLlm(input: LlmRequest, signal?: AbortSignal, onChunk?: (chunk: Record<string, unknown>) => void, target?: {
|
|
70
82
|
cwd: string;
|
|
71
83
|
profileId: string | null;
|
|
72
|
-
}, spend?:
|
|
84
|
+
}, spend?: LlmSpend, caller?: LlmCaller, causedBy?: string): Promise<LlmResult>;
|
|
73
85
|
export {};
|
package/dist/core/llm/run.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var
|
|
1
|
+
var Ae=Object.defineProperty;var c=(e,t)=>Ae(e,"name",{value:t,configurable:!0});import{randomUUID as Re}from"node:crypto";import{streamSimple as $e}from"@earendil-works/pi-ai/compat";import{APP_FAMILY as Ie,expandModelCandidates as ue,parseModelSpec as fe,probeRouteAvailability as Ce}from"../model-routes.js";import{readMergedLaunchConfig as me}from"../config.js";import{openModelRegistry as Oe}from"../runtime/model-registry.js";import{MAX_RATE_LIMIT_COOLDOWN_MS as pe,coolingUntilFor as he,isManagedProvider as K,markSubscriptionRateLimited as Se,markSubscriptionSuccess as Le,readSubscriptionPool as Ee,retryAfterMsFromHeaders as z,retryAfterMsFromError as Fe,refreshSubscriptionCredential as Ne,subscriptionNeedsSuccessWrite as De}from"../subscription-state.js";import{classifyRateLimit as Pe,describeRateLimitScope as _e,rateLimitHeaders as Te}from"../rate-limit-scope.js";import{RunError as s}from"../runs/operations.js";import{recognizeProviderError as re}from"../provider-error-recognition.js";import{isSafetyRefusal as Je}from"./refusal.js";import{findRefusal as We,payerOf as ge,refusalError as Ue,refusedMark as Be,writeCharge as ye}from"../ledger/index.js";import{personIdAsync as He}from"../canvas/person.js";import{getNode as we}from"../canvas/canvas.js";import{outboundToken as Ke}from"../providers/mint.js";import{discardFile as ze}from"../providers/token-cache.js";import{ProviderError as Xe}from"../providers/errors.js";import{appCandidates as Ge}from"./app-rungs.js";function Ye(e){return typeof e=="string"||e===null||Array.isArray(e)&&e.every(t=>t&&typeof t=="object"&&(t.type==="text"&&typeof t.text=="string"||t.type==="image_url"&&typeof t.image_url?.url=="string"&&/^data:image\/(png|jpeg|gif|webp);base64,[A-Za-z0-9+/]+={0,2}$/.test(t.image_url.url)))}c(Ye,"validContent");function be(e){return Array.isArray(e)?e.map(t=>{if(t.type==="text")return t;const[,n,i]=/^data:(image\/(?:png|jpeg|gif|webp));base64,(.*)$/.exec(t.image_url.url);return{type:"image",mimeType:n,data:i}}):e??""}c(be,"imageContent");function Ze(e,t){const n=(e instanceof Error?e.message:String(e)).split("; stack=",1)[0],i=re({message:n}).kind;return i!=="connection"&&i!=="connection-only"?e:new s(503,"upstream_model_unavailable",n.slice(0,500),void 0,{served_model:t})}c(Ze,"refreshFailure");function qt(e){if(!e||typeof e!="object"||Array.isArray(e))throw new s(400,"invalid_request","body must be an object");const t=e;if(!Array.isArray(t.messages)||!t.messages.every(n=>n&&typeof n=="object"&&["system","user","assistant","tool"].includes(n.role)&&Ye(n.content)))throw new s(400,"invalid_request","messages must be chat messages","messages");if(t.messages.some(n=>["system","assistant"].includes(n.role)&&typeof n.content!="string"&&n.content!==null))throw new s(400,"invalid_request","system and assistant content must be text","messages");if(t.model!==void 0&&typeof t.model!="string")throw new s(400,"invalid_request","model must be a string","model");if(t.model_policy!==void 0&&!["exact","substitute"].includes(t.model_policy))throw new s(400,"invalid_request","invalid model_policy","model_policy");if(t.payer!==void 0&&!["user","app"].includes(t.payer))throw new s(400,"invalid_request","invalid payer","payer");if(t.reasoning_effort!==void 0&&!["minimal","low","medium","high","xhigh","max"].includes(t.reasoning_effort))throw new s(400,"invalid_request","invalid reasoning_effort","reasoning_effort");if(t.stream!==void 0&&typeof t.stream!="boolean")throw new s(400,"invalid_request","stream must be boolean","stream");if(t.tools!==void 0&&(!Array.isArray(t.tools)||!t.tools.every(n=>n?.type==="function"&&typeof n.function?.name=="string"&&n.function.name.length>0&&(n.function.description===void 0||typeof n.function.description=="string")&&(n.function.parameters===void 0||n.function.parameters!==null&&typeof n.function.parameters=="object"&&!Array.isArray(n.function.parameters)&&n.function.parameters.type==="object"))))throw new s(400,"invalid_request","invalid tools","tools");if(t.tool_choice!==void 0&&t.tool_choice!=="auto"&&t.tool_choice!=="none"&&t.tool_choice!=="required"&&(typeof t.tool_choice!="object"||t.tool_choice===null||t.tool_choice.type!=="function"||typeof t.tool_choice.function?.name!="string"))throw new s(400,"invalid_request","invalid tool_choice","tool_choice");if(t.messages.some(n=>n.role==="assistant"&&n.tool_calls!==void 0&&(!Array.isArray(n.tool_calls)||!n.tool_calls.every(i=>i&&typeof i.id=="string"&&typeof i.function?.name=="string"&&typeof i.function.arguments=="string"&&Qe(i.function.arguments)))))throw new s(400,"invalid_request","invalid assistant tool_calls","messages");if(t.stop!==void 0&&!(typeof t.stop=="string"||Array.isArray(t.stop)&&t.stop.every(n=>typeof n=="string")))throw new s(400,"invalid_request","invalid stop","stop");if(t.seed!==void 0&&!Number.isSafeInteger(t.seed))throw new s(400,"invalid_request","invalid seed","seed");for(const[n,i]of[["temperature",t.temperature],["top_p",t.top_p],["max_tokens",t.max_tokens]])if(i!==void 0&&(typeof i!="number"||!Number.isFinite(i)||n==="temperature"&&(i<0||i>2)||n==="top_p"&&(i<0||i>1)||n==="max_tokens"&&(!Number.isSafeInteger(i)||i<1)))throw new s(400,"invalid_request",`invalid ${n}`,n);if(t.response_format!==void 0){const n=t.response_format;if(!n||typeof n!="object"||Array.isArray(n)||!["text","json_object","json_schema"].includes(n.type)||n.type==="json_schema"&&(typeof n.json_schema?.name!="string"||!n.json_schema.name||!n.json_schema.schema||typeof n.json_schema.schema!="object"||Array.isArray(n.json_schema.schema)))throw new s(400,"invalid_request","invalid response_format","response_format")}if(t.metadata!==void 0&&Buffer.byteLength(JSON.stringify(t.metadata)??"")>4096)throw new s(400,"invalid_request","metadata exceeds 4 KB","metadata");return t}c(qt,"parseLlmRequest");function Qe(e){try{const t=JSON.parse(e);return t!==null&&typeof t=="object"&&!Array.isArray(t)}catch{return!1}}c(Qe,"isJsonObject");function Ve(e){const t=Date.now(),n=e.messages.map(r=>r.role==="system"?{role:"system",content:r.content??"",timestamp:t}:r.role==="tool"?{role:"toolResult",toolCallId:r.tool_call_id??"",toolName:"",content:typeof r.content=="string"||r.content===null?[{type:"text",text:r.content??""}]:be(r.content),isError:!1,timestamp:t}:r.role==="assistant"?{role:"assistant",content:[...r.content?[{type:"text",text:r.content}]:[],...(r.tool_calls??[]).map(_=>({type:"toolCall",id:_.id,name:_.function.name,arguments:JSON.parse(_.function.arguments)}))],api:"openai-completions",provider:"openai",model:e.model??"",usage:{input:0,output:0,cacheRead:0,cacheWrite:0,totalTokens:0,cost:{input:0,output:0,cacheRead:0,cacheWrite:0,total:0}},stopReason:"stop",timestamp:t}:{role:"user",content:be(r.content),timestamp:t}),i=n.findIndex(r=>r.role!=="system"),d=n.slice(0,i<0?n.length:i).map(r=>r.content),y=d.join(`
|
|
2
2
|
|
|
3
|
-
`),s=e.tools?.map(({function:a})=>({name:a.name,description:a.description??"",parameters:a.parameters??{type:"object",properties:{}}}));return{..._?{systemPrompt:_}:{},messages:n.slice(k.length),...s?{tools:s}:{}}}u(Je,"contextOf");function me(e,t,n,r){const k=u(()=>{const s=ae(n,r),a=Object.values({...s.modelRoutes??{},...s.legacyModelRoutes??{}});return a.length?[s.modelLadders.defaultProvider,...s.modelRouting?.familyOrder??[],...a.map(g=>g.family)].find(g=>a.some(E=>E.family===g)):s.modelLadders.defaultProvider??"anthropic"},"ownerFamily");if(!e){const s=k();return{kind:"logical",family:s,strength:"strong",spec:`${s}/strong`}}const _=/^([^/]+)\/(ultra|strong|medium|light)$/.exec(e);if(_){if(_[1]===xe){const s=k();return{kind:"logical",family:s,strength:_[2],spec:`${s}/${_[2]}`}}return{kind:"logical",family:_[1],strength:_[2],spec:e}}return{kind:t==="exact"?"exact":"concrete",spec:e}}u(me,"requestFor");function We(e,t){const{input:n,output:r,cacheRead:k,cacheWrite:_}=e.cost;return n===0&&r===0&&k===0&&_===0?null:Number.isFinite(t)&&t>=0?t:null}u(We,"usdEquivalent");function He(e,t){return e.compat?.allowedFallbackModels?.find(r=>r.provider===e.provider&&r.model===t)}u(He,"allowedFallback");function ut(e){return e?{payer:e.payer??"user",sub:e.sub,grantee:e.grantee,inference_endpoint:e.inference_endpoint??null}:void 0}u(ut,"llmCallerOf");function Ke(e){return e instanceof Ne?e.code==="server_error"?new i(503,"upstream_model_unavailable",e.message):new i(404,"model_unavailable",e.message):e}u(Ke,"mintFailure");const ze=/\bmodel is not supported when using Codex with a ChatGPT account\b/i;function Be(e,t,n){if(!(e!=="openai-codex"||t===void 0||!ze.test(t)))return new i(404,"model_unavailable",t,void 0,{served_model:n})}u(Be,"codexAccountModelRejection");async function ft(e,t,n,r,k,_){const s=_?.payer==="app"?_:void 0;if(e.payer==="app"&&!s)throw new i(403,"payer_not_app","this grant is not app-paid");if(e.payer==="user"&&s)throw new i(400,"invalid_request","this grant is app-paid; payer cannot be user","payer");if(s&&!s.inference_endpoint)throw new i(404,"model_unavailable",`${s.grantee} is app-paid but its grant carries no inference endpoint`);const a=s?.inference_endpoint??void 0;s||await Le(k);const g=await Me(),E=u(c=>c.routeId!=="concrete"&&c.routeId!=="exact","configured"),ee=u(c=>{const h=g.find(c.providerId,c.modelId);return h!==void 0&&(!e.reasoning_effort||h.reasoning)&&(e.seed===void 0&&e.response_format===void 0||h.api==="openai-completions")&&(e.stop===void 0||["openai-completions","anthropic-messages"].includes(h.api))},"matchesFeatures"),pe=u(()=>{const c=me(e.model,e.model_policy,r?.cwd,r?.profileId),h=ie(c.kind==="exact"?{kind:"concrete",spec:c.spec}:c,r?.cwd,r?.profileId).filter(E);let d;if(c.kind==="logical")d=e.model_policy==="exact"?h.filter(m=>m.family===c.family&&m.strength===c.strength).slice(0,1):h;else{const m=se(c.spec),q=h.filter(M=>M.providerId===m?.providerId&&M.modelId===m.modelId&&(e.model_policy!=="exact"||M.thinkingLevel===m.thinkingLevel)&&ee(M));if(e.model_policy==="exact")d=q.slice(0,1);else if(q.length)d=q;else{const M=ae(r?.cwd,r?.profileId),w=[...Object.values(M.modelRoutes??{}).flatMap(v=>Object.entries(v.models)),...[M.modelLadders.anthropic,M.modelLadders.openai].flatMap(v=>Object.entries(v))].find(([,v])=>v===c.spec)?.[0],f=me(void 0,"substitute",r?.cwd,r?.profileId);d=w&&f.kind==="logical"?ie({...f,strength:w,spec:c.spec},r?.cwd,r?.profileId).filter(v=>E(v)&&v.strength===w):[]}}return d},"ownerCandidates");let R;if(a?R=De(a,e.model,e.model_policy==="exact").flatMap((c,h)=>{const d=se(c.model);return d?[{routeId:"app",credentialSource:"app",family:"app",strength:c.strength,...d,rank:h}]:[]}):R=pe(),R=R.filter(ee),R.length===0)throw e.model_policy==="exact"?new i(400,"substitution_refused","no eligible model route is configured"):new i(404,"model_unavailable","no eligible model route is configured");const te=`chatcmpl-${ve()}`;let I=1/0,b,z;for(const c of R){if(!s&&!ke(c,g).authenticated)continue;const h=g.find(c.providerId,c.modelId);if(!h)continue;const d=a?{...h,baseUrl:`${a.base_url}/${h.provider}`}:h,m=c.providerId,q=!s&&H(m)?qe(m).filter(w=>!w.authFailure):[],M=q.filter(w=>le(w,d.id)<=Date.now());if(q.length&&!M.length){const w=Math.min(...q.map(f=>le(f,d.id)));w<I&&(I=w,z=`${d.provider}/${d.id}`);continue}const oe=s?[void 0,void 0]:q.length?M:[void 0];for(const[w,f]of oe.entries()){const v=Date.now();let ne=f?.access;if(f&&f.expires<=Date.now()&&H(m)){const o=g.getProvider(m)?.auth.oauth;if(!o)throw new i(503,"upstream_model_unavailable",`no OAuth refresh for ${m}`,void 0,{served_model:`${d.provider}/${d.id}`});ne=(await Re(m,f.label,async(x,re)=>{const W=await o.refresh({type:"oauth",refresh:x,access:"",expires:0,...re?{clientId:re}:{}},t??new AbortController().signal).catch(ge=>{throw Te(ge,`${d.provider}/${d.id}`)}),Q=W.clientId;return{refresh:W.refresh,access:W.access,expires:W.expires,...typeof Q=="string"&&Q?{clientId:Q}:{}}})).access}const he=Je(e);let F;if(s&&a)try{F=await Ee({audience:a.base_url,sub:s.sub,grantee:s.grantee,initiating_app:s.grantee,scope:["crtr:llm"]},{signal:t})}catch(o){throw Ke(o)}const C=f||s?void 0:await g.getApiKeyAndHeaders(d);if(C&&!C.ok)continue;const p=`${d.provider}/${d.id}`,S=e.model??p;let A=!1,L,j=3e4,$;const B=[],X=[],N=[];let l,D;const P=u((o,y=null)=>({id:te,object:"chat.completion.chunk",created:Math.floor(v/1e3),model:p,served_model:p,requested_model:S,substituted:S!==p&&!/^([^/]+)\/(ultra|strong|medium|light)$/.test(S),choices:[{index:0,delta:o,finish_reason:y}]}),"chunk"),T=u(o=>{B.push(o),n?.(o)},"emit"),_e=we(d,he,{apiKey:F?.access_token??ne??(C?.ok?C.apiKey:void 0),...C?.ok?{headers:C.headers}:{},signal:t,reasoning:e.reasoning_effort??c.thinkingLevel,...e.temperature!==void 0?{temperature:e.temperature}:{},...e.max_tokens!==void 0?{maxTokens:e.max_tokens}:{},...e.top_p!==void 0?{samplingParams:{top_p:e.top_p}}:{},...e.tool_choice==="none"?{toolChoice:"none"}:{},onPayload:u(o=>{if(!o||typeof o!="object")return;const y=e.tool_choice,x=y==="required"?d.api==="anthropic-messages"?{type:"any"}:"required":typeof y=="object"&&y!==null?d.api==="anthropic-messages"?{type:"tool",name:y.function.name}:y:void 0;return{...o,...x?{tool_choice:x}:{},...e.stop!==void 0?{[d.api==="anthropic-messages"?"stop_sequences":"stop"]:typeof e.stop=="string"?[e.stop]:e.stop}:{},...e.seed!==void 0?{seed:e.seed}:{},...e.response_format!==void 0?{response_format:e.response_format}:{}}},"onPayload"),fetch:u(async(o,y)=>{const x=await fetch(o,y);return L=x.status,x.status===429&&(A=!0,$=x.headers,j=K(x.headers)??15e3),x},"fetch"),onResponse:u(o=>{o.status===429&&(A=!0,$=o.headers,j=K(o.headers)??15e3)},"onResponse")});try{for await(const o of _e)o.type==="text_delta"&&(X.push(o.delta),T(P({content:o.delta}))),o.type==="thinking_delta"&&(N.push(o.delta),T(P({reasoning_content:o.delta}))),o.type==="done"&&(l=o.message),o.type==="error"&&(l=o.error)}catch(o){const y=$e(o);$===void 0&&o&&typeof o=="object"&&"headers"in o&&Object.keys(Se(o.headers)).length&&($=o.headers);const x=V({status:o&&typeof o=="object"&&"status"in o?o.status:void 0,message:o instanceof Error?o.message:String(o)});if(s)D=o;else{if(!A&&x.kind!=="rate-limit")throw B.length?new i(503,"upstream_model_unavailable",o instanceof Error?o.message:String(o),void 0,{served_model:p}):o;A=!0,j=y??j}}if(s){if(L===401){if(F&&Fe(F.key),w===0)continue;throw new i(404,"model_unavailable",`${a.base_url} refuses this runtime's tokens`,void 0,{served_model:p})}if(A&&K($)===void 0)throw new i(503,"upstream_model_unavailable",`${p} was rate-limited without a retry-after`,void 0,{served_model:p});if(!A&&(D!==void 0||L!==void 0&&L>=500))throw new i(503,"upstream_model_unavailable",D instanceof Error?D.message:l?.errorMessage??"inference endpoint failed",void 0,{served_model:p})}if(!A&&l?.stopReason==="error"&&V({message:l.errorMessage}).kind==="rate-limit"&&(A=!0,j=15e3),A){const o=Ce($,d.id);if(K($)===void 0&&o.resetAt!==void 0&&(j=Math.max(j,o.resetAt-Date.now())),b={provider:m,model:d.id,...f?{account:f.label}:{},observation:o},console.error(`[llm] 429 from ${p}${f?` account "${f.label}"`:""}: scope=${ce(o.scope)} retry_after_ms=${j} headers=${JSON.stringify(o.headers)}`),f&&H(m)&&await je(m,f.label,j,v,Date.now(),o.scope),Date.now()+Math.min(j,de)<I&&(I=Date.now()+Math.min(j,de),z=p),X.length||N.length)throw new i(503,"service_unavailable","vendor rate limit after output began",void 0,{served_model:p});if(s)break;continue}const U=Oe(l);if(L===400&&e.tool_choice!==void 0&&e.tool_choice!=="auto"&&e.tool_choice!=="none"&&/\btool[_ ]choice\b/i.test(l?.errorMessage??"")&&/not supported|does not support|unsupported|cannot|must be auto/i.test(l?.errorMessage??""))throw new i(400,"invalid_request",l.errorMessage,"tool_choice",{served_model:p});if(l?.stopReason==="error"){const o=Be(d.provider,l.errorMessage,p);if(o)throw o}if(!l||l.stopReason==="error"&&!U||l.stopReason==="aborted")throw new i(503,"upstream_model_unavailable",l?.errorMessage??"model request failed",void 0,{served_model:p});f&&H(m)&&Ie(f,d.id)&&await Ae(m,f.label,v,d.id);const G=l.content.filter(o=>o.type==="toolCall").map(o=>({id:o.id,type:"function",function:{name:o.name,arguments:JSON.stringify(o.arguments)}})),Y=U?"content_filter":l.stopReason==="toolUse"?"tool_calls":l.stopReason==="length"?"length":"stop",Z=l.responseModel?He(d,l.responseModel):void 0,O=Z?`${d.provider}/${Z.model}`:p,J={prompt_tokens:l.usage.input,completion_tokens:l.usage.output,total_tokens:l.usage.totalTokens,cache_read_tokens:l.usage.cacheRead,cache_write_tokens:l.usage.cacheWrite,usd_equivalent:We(Z??d,l.usage.cost.total),served_model:O};s?await ue(s.grantee,"app",O,l.usage,J.usd_equivalent):k&&await ue(k.grantee,"user",O,l.usage,J.usd_equivalent);const ye={id:te,object:"chat.completion",created:Math.floor(v/1e3),model:O,served_model:O,requested_model:S,substituted:S!==O&&!/^([^/]+)\/(ultra|strong|medium|light)$/.test(S),choices:[{index:0,message:{role:"assistant",content:X.join("")||null,...N.length?{reasoning_content:N.join("")}:{},...G.length?{tool_calls:G}:{},...U?{refusal:l.errorMessage??"Content filtered"}:{}},finish_reason:Y}],usage:J,...e.metadata!==void 0?{metadata:e.metadata}:{}};for(const[o,y]of G.entries())T(P({tool_calls:[{index:o,...y}]}));return T({...P({},Y),...U?{choices:[{index:0,delta:{},finish_reason:Y,message:{refusal:l.errorMessage??"Content filtered"}}]}:{},usage:J}),{completion:ye,chunks:B}}}throw I!==1/0?new i(429,"all_routes_exhausted","all eligible model routes are rate-limited",void 0,{retry_after_s:Math.max(1,Math.ceil((I-Date.now())/1e3)),served_model:b?`${b.provider}/${b.model}`:z,...b?{rate_limit:{provider:b.provider,model:b.model,...b.account?{account:b.account}:{},scope:ce(b.observation.scope),...b.observation.claim?{claim:b.observation.claim}:{},headers:b.observation.headers}}:{}},void 0,!0):e.model_policy==="exact"?new i(400,"substitution_refused","the requested model is unavailable"):new i(404,"model_unavailable","no usable model route is available")}u(ft,"runLlm");export{ut as llmCallerOf,ct as parseLlmRequest,ft as runLlm};
|
|
3
|
+
`),h=e.tools?.map(({function:r})=>({name:r.name,description:r.description??"",parameters:r.parameters??{type:"object",properties:{}}}));return{...y?{systemPrompt:y}:{},messages:n.slice(d.length),...h?{tools:h}:{}}}c(Ve,"contextOf");function ve(e,t,n,i){const d=c(()=>{const h=me(n,i),r=Object.values({...h.modelRoutes??{},...h.legacyModelRoutes??{}});return r.length?[h.modelLadders.defaultProvider,...h.modelRouting?.familyOrder??[],...r.map(_=>_.family)].find(_=>r.some($=>$.family===_)):h.modelLadders.defaultProvider??"anthropic"},"ownerFamily");if(!e){const h=d();return{kind:"logical",family:h,strength:"strong",spec:`${h}/strong`}}const y=/^([^/]+)\/(ultra|strong|medium|light)$/.exec(e);if(y){if(y[1]===Ie){const h=d();return{kind:"logical",family:h,strength:y[2],spec:`${h}/${y[2]}`}}return{kind:"logical",family:y[1],strength:y[2],spec:e}}return{kind:t==="exact"?"exact":"concrete",spec:e}}c(ve,"requestFor");function et(e,t){const{input:n,output:i,cacheRead:d,cacheWrite:y}=e.cost;return n===0&&i===0&&d===0&&y===0?null:Number.isFinite(t)&&t>=0?t:null}c(et,"usdEquivalent");function tt(e,t){return e.compat?.allowedFallbackModels?.find(i=>i.provider===e.provider&&i.model===t)}c(tt,"allowedFallback");function Mt(e){return e?{payer:e.payer??"user",sub:e.sub,grantee:e.grantee,inference_endpoint:e.inference_endpoint??null}:void 0}c(Mt,"llmCallerOf");function ot(e){return e instanceof Xe?e.code==="server_error"?new s(503,"upstream_model_unavailable",e.message):new s(404,"model_unavailable",e.message):e}c(ot,"mintFailure");const nt=/\bmodel is not supported when using Codex with a ChatGPT account\b/i;function rt(e,t,n){if(!(e!=="openai-codex"||t===void 0||!nt.test(t)))return new s(404,"model_unavailable",t,void 0,{served_model:n})}c(rt,"codexAccountModelRejection");function it(e){return e.get("request-id")??e.get("x-request-id")}c(it,"vendorRequestId");async function jt(e,t,n,i,d,y,h){const r=y?.payer==="app"?y:void 0;if(e.payer==="app"&&!r)throw new s(403,"payer_not_app","this grant is not app-paid");if(e.payer==="user"&&r)throw new s(400,"invalid_request","this grant is app-paid; payer cannot be user","payer");if(r&&!r.inference_endpoint)throw new s(404,"model_unavailable",`${r.grantee} is app-paid but its grant carries no inference endpoint`);const _=r?.inference_endpoint??void 0,$=d===void 0?null:r?.sub??d.sub??await He(),E=await Oe(),ie=c(u=>u.routeId!=="concrete"&&u.routeId!=="exact","configured"),se=c(u=>{const g=E.find(u.providerId,u.modelId);return g!==void 0&&(!e.reasoning_effort||g.reasoning)&&(e.seed===void 0&&e.response_format===void 0||g.api==="openai-completions")&&(e.stop===void 0||["openai-completions","anthropic-messages"].includes(g.api))},"matchesFeatures"),xe=c(()=>{const u=ve(e.model,e.model_policy,i?.cwd,i?.profileId),g=ue(u.kind==="exact"?{kind:"concrete",spec:u.spec}:u,i?.cwd,i?.profileId).filter(ie);let a;if(u.kind==="logical")a=e.model_policy==="exact"?g.filter(f=>f.family===u.family&&f.strength===u.strength).slice(0,1):g;else{const f=fe(u.spec),A=g.filter(q=>q.providerId===f?.providerId&&q.modelId===f.modelId&&(e.model_policy!=="exact"||q.thinkingLevel===f.thinkingLevel)&&se(q));if(e.model_policy==="exact")a=A.slice(0,1);else if(A.length)a=A;else{const q=me(i?.cwd,i?.profileId),k=[...Object.values(q.modelRoutes??{}).flatMap(v=>Object.entries(v.models)),...[q.modelLadders.anthropic,q.modelLadders.openai].flatMap(v=>Object.entries(v))].find(([,v])=>v===u.spec)?.[0],m=ve(void 0,"substitute",i?.cwd,i?.profileId);a=k&&m.kind==="logical"?ue({...m,strength:k,spec:u.spec},i?.cwd,i?.profileId).filter(v=>ie(v)&&v.strength===k):[]}}return a},"ownerCandidates");let C;if(_?C=Ge(_,e.model,e.model_policy==="exact").flatMap((u,g)=>{const a=fe(u.model);return a?[{routeId:"app",credentialSource:"app",family:"app",strength:u.strength,...a,rank:g}]:[]}):C=xe(),C=C.filter(se),C.length===0)throw e.model_policy==="exact"?new s(400,"substitution_refused","no eligible model route is configured"):new s(404,"model_unavailable","no eligible model route is configured");const D=`chatcmpl-${Re()}`;let O=1/0,b,X,G;const ae=c(async()=>h??(d?.node?(await we(d.node))?.caused_by??null:null)??(d?.run?(await we(d.run))?.caused_by??null:null),"causeOf");for(const u of C){if(!r&&!Ce(u,E).authenticated)continue;const g=E.find(u.providerId,u.modelId);if(!g)continue;const a=_?{...g,baseUrl:`${_.base_url}/${g.provider}`}:g,f=u.providerId,A=!r&&K(f)?Ee(f).filter(k=>!k.authFailure):[],q=A.filter(k=>he(k,a.id)<=Date.now());if(A.length&&!q.length){const k=Math.min(...A.map(m=>he(m,a.id)));k<O&&(O=k,X=`${a.provider}/${a.id}`);continue}const le=r?[void 0,void 0]:A.length?q:[void 0];for(const[k,m]of le.entries()){const v=Date.now();let de=m?.access;if(m&&m.expires<=Date.now()&&K(f)){const o=E.getProvider(f)?.auth.oauth;if(!o)throw new s(503,"upstream_model_unavailable",`no OAuth refresh for ${f}`,void 0,{served_model:`${a.provider}/${a.id}`});de=(await Ne(f,m.label,async(x,ce)=>{const H=await o.refresh({type:"oauth",refresh:x,access:"",expires:0,...ce?{clientId:ce}:{}},t??new AbortController().signal).catch(je=>{throw Ze(je,`${a.provider}/${a.id}`)}),ne=H.clientId;return{refresh:H.refresh,access:H.access,expires:H.expires,...typeof ne=="string"&&ne?{clientId:ne}:{}}})).access}const ke=Ve(e),S=m||r?void 0:await E.getApiKeyAndHeaders(a);if(S&&!S.ok)continue;const p=`${a.provider}/${a.id}`,L=e.model??p,R=r?ge({call:"model",route:"endpoint",grantee:r.grantee}):$===null?null:ge({call:"model",route:m?"subscription":"key",sub:$});if(d!==void 0&&R!==null){const o=await We({scope:"call",payer:R.payer,funding:R.funding,sub:$,grantee:d.grantee,provider:f});if(o!==null){await ye({request:d.request??D,kind:"model",what:p,usd:null,payer:R.payer,funding:R.funding,sub:$,grantee:d.grantee,node:d.node??null,run:d.run??null,provider:f,causedBy:await ae(),refused:Be(o)}),G??=o;break}}let P;if(r&&_)try{P=await Ke({audience:_.base_url,sub:r.sub,grantee:r.grantee,initiating_app:r.grantee,scope:["crtr:llm"]},{signal:t})}catch(o){throw ot(o)}let j=!1,F,Y=null,M=3e4,I;const Z=[],Q=[],T=[];let l,J;const W=c((o,w=null)=>({id:D,object:"chat.completion.chunk",created:Math.floor(v/1e3),model:p,served_model:p,requested_model:L,substituted:L!==p&&!/^([^/]+)\/(ultra|strong|medium|light)$/.test(L),choices:[{index:0,delta:o,finish_reason:w}]}),"chunk"),U=c(o=>{Z.push(o),n?.(o)},"emit"),qe=$e(a,ke,{apiKey:P?.access_token??de??(S?.ok?S.apiKey:void 0),...S?.ok?{headers:S.headers}:{},signal:t,reasoning:e.reasoning_effort??u.thinkingLevel,...e.temperature!==void 0?{temperature:e.temperature}:{},...e.max_tokens!==void 0?{maxTokens:e.max_tokens}:{},...e.top_p!==void 0?{samplingParams:{top_p:e.top_p}}:{},...e.tool_choice==="none"?{toolChoice:"none"}:{},onPayload:c(o=>{if(!o||typeof o!="object")return;const w=e.tool_choice,x=w==="required"?a.api==="anthropic-messages"?{type:"any"}:"required":typeof w=="object"&&w!==null?a.api==="anthropic-messages"?{type:"tool",name:w.function.name}:w:void 0;return{...o,...x?{tool_choice:x}:{},...e.stop!==void 0?{[a.api==="anthropic-messages"?"stop_sequences":"stop"]:typeof e.stop=="string"?[e.stop]:e.stop}:{},...e.seed!==void 0?{seed:e.seed}:{},...e.response_format!==void 0?{response_format:e.response_format}:{}}},"onPayload"),fetch:c(async(o,w)=>{const x=await fetch(o,w);return F=x.status,Y=it(x.headers)??Y,x.status===429&&(j=!0,I=x.headers,M=z(x.headers)??15e3),x},"fetch"),onResponse:c(o=>{o.status===429&&(j=!0,I=o.headers,M=z(o.headers)??15e3)},"onResponse")});try{for await(const o of qe)o.type==="text_delta"&&(Q.push(o.delta),U(W({content:o.delta}))),o.type==="thinking_delta"&&(T.push(o.delta),U(W({reasoning_content:o.delta}))),o.type==="done"&&(l=o.message),o.type==="error"&&(l=o.error)}catch(o){const w=Fe(o);I===void 0&&o&&typeof o=="object"&&"headers"in o&&Object.keys(Te(o.headers)).length&&(I=o.headers);const x=re({status:o&&typeof o=="object"&&"status"in o?o.status:void 0,message:o instanceof Error?o.message:String(o)});if(r)J=o;else{if(!j&&x.kind!=="rate-limit")throw Z.length?new s(503,"upstream_model_unavailable",o instanceof Error?o.message:String(o),void 0,{served_model:p}):o;j=!0,M=w??M}}if(r){if(F===401){if(P&&ze(P.key),k===0)continue;throw new s(404,"model_unavailable",`${_.base_url} refuses this runtime's tokens`,void 0,{served_model:p})}if(j&&z(I)===void 0)throw new s(503,"upstream_model_unavailable",`${p} was rate-limited without a retry-after`,void 0,{served_model:p});if(!j&&(J!==void 0||F!==void 0&&F>=500))throw new s(503,"upstream_model_unavailable",J instanceof Error?J.message:l?.errorMessage??"inference endpoint failed",void 0,{served_model:p})}if(!j&&l?.stopReason==="error"&&re({message:l.errorMessage}).kind==="rate-limit"&&(j=!0,M=15e3),j){const o=Pe(I,a.id);if(z(I)===void 0&&o.resetAt!==void 0&&(M=Math.max(M,o.resetAt-Date.now())),b={provider:f,model:a.id,...m?{account:m.label}:{},observation:o},console.error(`[llm] 429 from ${p}${m?` account "${m.label}"`:""}: scope=${_e(o.scope)} retry_after_ms=${M} headers=${JSON.stringify(o.headers)}`),m&&K(f)&&await Se(f,m.label,M,v,Date.now(),o.scope),Date.now()+Math.min(M,pe)<O&&(O=Date.now()+Math.min(M,pe),X=p),Q.length||T.length)throw new s(503,"service_unavailable","vendor rate limit after output began",void 0,{served_model:p});if(r)break;continue}const B=Je(l);if(F===400&&e.tool_choice!==void 0&&e.tool_choice!=="auto"&&e.tool_choice!=="none"&&/\btool[_ ]choice\b/i.test(l?.errorMessage??"")&&/not supported|does not support|unsupported|cannot|must be auto/i.test(l?.errorMessage??""))throw new s(400,"invalid_request",l.errorMessage,"tool_choice",{served_model:p});if(l?.stopReason==="error"){const o=rt(a.provider,l.errorMessage,p);if(o)throw o}if(!l||l.stopReason==="error"&&!B||l.stopReason==="aborted")throw new s(503,"upstream_model_unavailable",l?.errorMessage??"model request failed",void 0,{served_model:p});m&&K(f)&&De(m,a.id)&&await Le(f,m.label,v,a.id);const V=l.content.filter(o=>o.type==="toolCall").map(o=>({id:o.id,type:"function",function:{name:o.name,arguments:JSON.stringify(o.arguments)}})),ee=B?"content_filter":l.stopReason==="toolUse"?"tool_calls":l.stopReason==="length"?"length":"stop",te=l.responseModel?tt(a,l.responseModel):void 0,N=te?`${a.provider}/${te.model}`:p,oe={prompt_tokens:l.usage.input,completion_tokens:l.usage.output,total_tokens:l.usage.totalTokens,cache_read_tokens:l.usage.cacheRead,cache_write_tokens:l.usage.cacheWrite,usd_equivalent:et(te??a,l.usage.cost.total),served_model:N};d!==void 0&&R!==null&&await ye({request:d.request??D,kind:"model",what:N,units:{input:l.usage.input,output:l.usage.output,cache_read:l.usage.cacheRead,cache_write:l.usage.cacheWrite},usd:oe.usd_equivalent,payer:R.payer,funding:R.funding,sub:$,grantee:d.grantee,node:d.node??null,run:d.run??null,provider:f,causedBy:await ae(),vendorRef:Y});const Me={id:D,object:"chat.completion",created:Math.floor(v/1e3),model:N,served_model:N,requested_model:L,substituted:L!==N&&!/^([^/]+)\/(ultra|strong|medium|light)$/.test(L),choices:[{index:0,message:{role:"assistant",content:Q.join("")||null,...T.length?{reasoning_content:T.join("")}:{},...V.length?{tool_calls:V}:{},...B?{refusal:l.errorMessage??"Content filtered"}:{}},finish_reason:ee}],usage:oe,...e.metadata!==void 0?{metadata:e.metadata}:{}};for(const[o,w]of V.entries())U(W({tool_calls:[{index:o,...w}]}));return U({...W({},ee),...B?{choices:[{index:0,delta:{},finish_reason:ee,message:{refusal:l.errorMessage??"Content filtered"}}]}:{},usage:oe}),{completion:Me,chunks:Z}}}throw G!==void 0?Ue(G):O!==1/0?new s(429,"all_routes_exhausted","all eligible model routes are rate-limited",void 0,{retry_after_s:Math.max(1,Math.ceil((O-Date.now())/1e3)),served_model:b?`${b.provider}/${b.model}`:X,...b?{rate_limit:{provider:b.provider,model:b.model,...b.account?{account:b.account}:{},scope:_e(b.observation.scope),...b.observation.claim?{claim:b.observation.claim}:{},headers:b.observation.headers}}:{}},void 0,!0):e.model_policy==="exact"?new s(400,"substitution_refused","the requested model is unavailable"):new s(404,"model_unavailable","no usable model route is available")}c(jt,"runLlm");export{Mt as llmCallerOf,qt as parseLlmRequest,jt as runLlm};
|
|
@@ -2,6 +2,7 @@ import type { ManifestHttpLeaf, ManifestBranch, ManifestRootEntry } from '../../
|
|
|
2
2
|
import type { ValidatedCommandManifest } from '../../api/command-manifest/manifest.js';
|
|
3
3
|
import type { ProviderCaller, ProviderCallInput, ProviderRequest } from '../../daemon/api/handlers/providers.js';
|
|
4
4
|
import { ProviderError } from './errors.js';
|
|
5
|
+
import type { Funding } from '../ledger/types.js';
|
|
5
6
|
/** `tool` is a canonical command path, relative to the provider and never provider-prefixed. `hidden` is true for a leaf declared hidden or under a hidden branch: it stays callable by its exact path but is never listed. */
|
|
6
7
|
export interface ProviderLeaf {
|
|
7
8
|
tool: string;
|
|
@@ -58,8 +59,13 @@ export interface ProviderResponseContext {
|
|
|
58
59
|
grantee: string;
|
|
59
60
|
/** The outbound token's payer: the principal the directory charges for this call. */
|
|
60
61
|
payer: string;
|
|
61
|
-
/**
|
|
62
|
+
/** The app the charge is attributed to: the calling app, or `app:terminal` for the person (whose outbound identity is their sub). */
|
|
62
63
|
ledger_grantee: string;
|
|
64
|
+
/** `bill` when the person pays, `endpoint` when the app pays (`payerOf`). */
|
|
65
|
+
funding: Funding;
|
|
66
|
+
/** The calling node, and the `Crtr-Caused-By` the call arrived with; null when none. */
|
|
67
|
+
node_id: string | null;
|
|
68
|
+
caused_by: string | null;
|
|
63
69
|
jti: string;
|
|
64
70
|
status: number;
|
|
65
71
|
headers: Record<string, string | string[] | undefined>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var te=Object.defineProperty;var v=(e,r)=>te(e,"name",{value:r,configurable:!0});import{validateDeclaredResult as U}from"../../api/command-manifest/result.js";import{callerAllows as oe,requireGroup as ie}from"../../daemon/api/handlers/providers.js";import{terminalGrant as ne}from"../grants/mirror.js";import{UNCAPPED_GRANTEE as se}from"../usage/ledger.js";import{listInstalledPlugins as ae}from"../resolver.js";import{ProviderError as l}from"./errors.js";import{resolveProviderRef as de}from"./roots.js";import{providerToolPath as ue}from"../plugin-objects-manifest.js";import{ensureProviderBundle as le,refreshProviderBundle as pe,resolveProviderBundle as B,unavailableProviderError as ce}from"./bundles.js";import{prepareFileCall as fe,resignForRetry as z,resolveFileResult as Q}from"./files.js";import{consumeApproval as me,requireProviderApproval as ve}from"./approval.js";import{outboundToken as ge}from"./mint.js";import{discardFile as he}from"./token-cache.js";import{registerProviderCall as we}from"./inflight.js";import{buildRequestPlan as be}from"../command-plugins/transport/http-plan.js";import{newTraceId as ye}from"../../shared/traceparent.js";import{sendProviderRequest as _e,ProviderTransportError as Ae}from"./request.js";import{acceptProviderReceipt as je}from"./receipts.js";import{writeProviderAudit as ke}from"./audit.js";import{selectDevice as Pe,sendDeviceCall as qe,deviceFailure as Ee,deviceUnreachable as V,DEFAULT_DEVICE_REQUEST_MS as $e}from"./device.js";import{isLibsSearch as K,wantsBundling as Ce,callLibsSearch as Re,bundleExec as Ie,mapLibOutcome as Se,reportLibCalls as Te}from"./device-libs.js";import{directoryIssuer as Ne,ownMachineId as De}from"../peer/directory.js";import{formatCrtrCaller as W}from"../command-plugins/caller-header.js";import{getNode as Fe}from"../canvas/canvas.js";import{envelopeForProviderCaller as Me}from"../peer/envelope.js";function X(e){const r=[],n=v((c,t,o)=>{const s=[...t,c.name],a=o||c.tier==="hidden";if(c.kind==="branch"){for(const g of c.children)n(g,s,a);return}const j=ue(e.roots.length,s);r.push({tool:j,leaf:c,hidden:a})},"walk");for(const c of e.roots)n(c,[],!1);return r}v(X,"providerLeaves");function Y(e){if(e.kind!=="branch")return null;const r=[];for(const h of e.children)if(h.kind==="branch"){const _=Y(h);_&&r.push(_)}else if("group"in h&&h.group){const{kind:_,name:d,description:A,whenToUse:w,tier:b,summary:k,params:P,output:i,effects:p,group:m}=h;r.push({kind:_,name:d,description:A,whenToUse:w,...b===void 0?{}:{tier:b},summary:k,params:P,output:i,effects:p,group:m})}if(r.length===0)return null;const{kind:n,name:c,description:t,whenToUse:o,tier:s,summary:a,model:j,rootEntry:g}=e;return{kind:n,name:c,description:t,whenToUse:o,...s===void 0?{}:{tier:s},summary:a,...j===void 0?{}:{model:j},...g===void 0?{}:{rootEntry:g},children:r}}v(Y,"providerHelpBranch");async function hr(e,r){const n=await B(r),c=X(n.commands),t=ae("user").find(o=>o.name===r)?.manifest.description??r;return{provider:r,status:"available",major:n.major,display_name:t,transport:n.transport.kind,groups:n.provider.groups.filter(o=>oe(e,`${r}:${o.group}`)).map(o=>({group:o.group,leaves:c.filter(({leaf:s,hidden:a})=>!a&&s.group===o.group).map(({tool:s,leaf:a})=>({tool:s,description:a.description,summary:a.summary,params:a.params,output:a.output}))})),commands:n.commands.roots.flatMap(o=>{const s=Y(o);return s?[s]:[]})}}v(hr,"providerTools");async function Oe(e){return await je(e.headers["crtr-receipt"],e)}v(Oe,"onProviderResponse");async function Ue(e){if(e.class==="person"){const r=(await ne())?.sub;if(!r)throw new l("grant_revoked","This machine has no active Northlight grant for your terminal. Run `crtr sys join` again from /account/machines.");return{sub:r,grantee:r}}if(!e.sub||!e.grantee)throw new l("grant_revoked","the caller has no active grant");return{sub:e.sub,grantee:e.grantee}}v(Ue,"identity");function Be(e,r){return[`${e.id}:${r.group}`]}v(Be,"callScope");function Le(e,r){const n=X(e.commands).find(c=>c.tool===r);if(!n)throw new l("not_found",`tool "${r}" is not in provider "${e.id}"`,{param:"tool"});if(!n.leaf.group)throw new l("not_found",`tool "${r}" has no group`,{param:"tool"});return n.leaf}v(Le,"leafFor");function L(e){if(!e||typeof e!="object"||Array.isArray(e))return{};const r=e.error;return!r||typeof r!="object"||Array.isArray(r)?{}:r}v(L,"errorBody");function Je(e){const r=Array.isArray(e)?e[0]:e;if(!r)return;const n=Number(r);if(Number.isFinite(n)&&n>=0)return n;const c=Date.parse(r);return Number.isFinite(c)?Math.max(0,Math.ceil((c-Date.now())/1e3)):void 0}v(Je,"retryAfter");function N(e,r,n,c=!1){const t=L(r),o=typeof t.code=="string"?t.code:void 0,s=typeof t.message=="string"?t.message:`provider answered HTTP ${e}`,a=typeof t.field=="string"?t.field:void 0,g={origin:"provider",details:{code:o??null,message:s,...a?{field:a}:{},...typeof t.next=="string"?{next:t.next}:{},...t.received!==void 0?{received:t.received}:{},status:e},...a?{param:a}:{}};return e===429?new l("provider_rate_limited",s,{...g,retry_after_s:Je(n["retry-after"])}):e===401||e>=500?new l("provider_unavailable",s,g):e===403&&o==="provider_refused"?new l("provider_refused",s,g):e===403&&o==="approval_required"?new l("provider_error",c?"provider asked for approval again":"provider approval question is invalid",{...g,status:e}):new l("provider_error",s,{...g,status:e})}v(N,"mapProviderResponse");function Z(e,r){return JSON.stringify({major:e.major,endpoint:e.transport.kind==="http"?e.transport.endpoint:null,baseUrl:e.commands.baseUrl??null,rest:r.rest,params:r.params,output:r.output})}v(Z,"approvalShape");async function He(e){const r=e.origin!==void 0?W({node:e.origin.node??void 0,run:e.origin.run??void 0,machine:e.origin.machine}):W({node:e.node_id??void 0,run:e.run_id??void 0,profile:e.node_id?(await Fe(e.node_id))?.profile_id??void 0:void 0,machine:Ne()!==null?De():void 0});return r===""?{}:{"Crtr-Caller":r}}v(He,"crtrCallerHeader");async function wr(e,r,n){const c=de(r.provider);if(c===null)throw new l("not_found",`provider "${r.provider}" is not available`,{param:"provider"});const t={...r,provider:c},o=new AbortController,s=v(()=>o.abort(n.signal.reason),"abort");n.signal.aborted?s():n.signal.addEventListener("abort",s,{once:!0});let a=n.requestId;const j=n.traceId??ye(),g=we({request_id:a,run_id:e.run_id,node_id:e.node_id,controller:o});let h,_,d,A,w,b,k,P="allowed";try{try{await le(t.provider)}catch{throw ce(t.provider)}let i=await B(t.provider,t.version),p=!1,m,D,q,J=!1,H=!1,F,x=0;for(;;){const y=Le(i,t.tool);if(d=`${i.id}:${y.group}`,ie(e,i.id,y.group),i.transport.kind!=="machine"&&t.machine!==void 0)throw new l("invalid_argument",`provider "${i.id}" is not served by a device, so it takes no machine`,{param:"machine"});i.transport.kind==="machine"&&F===void 0&&(F=await Pe(t.machine,void 0,{newest:K(i.major,t.tool)}),x=Date.now()+(i.commands.timeouts?.requestMs??$e));let M=null;if(t.approval&&!J){const u=await me(e,t,Z(i,y));q=u.option,M=u.prepared,k=t.approval,a=u.requestId,J=!0}const C={params:y.params.filter(u=>"type"in u&&u.type==="file").map(u=>u.name),output:y.output.find(u=>u.type==="file")?.name??null},G=JSON.stringify(C);if(D!==void 0&&D!==G)throw new l("provider_bad_response","the refreshed manifest changed the tool file contract",{origin:"provider",details:{status:409,message:"manifest_stale changed the tool file contract"}});D=G,M&&(m=await z(e,C,t.arguments,M,{signal:o.signal})),m??=await fe(e,C,t.arguments,{signal:o.signal});const{sub:O,grantee:R}=await Ue(e);if(i.transport.kind==="machine"){const u=await xe(e,i,t,y,m,{sub:O,requestId:a,deadlineAt:x,signal:o.signal,machine:F});return b=u.responder,h=u.cleanup,{status:200,body:u.result}}const E=await ge({audience:i.transport.endpoint,sub:O,grantee:R,initiating_app:R,scope:Be(i,y)},{signal:o.signal});A=E.jti;const ee={registration:{name:i.id,endpoint:i.transport.endpoint},...i.commands.baseUrl?{baseUrl:i.commands.baseUrl}:{},...i.commands.timeouts?{timeouts:i.commands.timeouts}:{},params:y.params,rest:y.rest,output:y.output,commandPath:[i.id,...t.tool.split(" ")]},re=be(ee,m.arguments,void 0,{authorization:`Bearer ${E.access_token}`,requestId:a,traceId:j,fileMode:"pass-through",extraHeaders:{...e.run_id?{"Crtr-Run-Id":e.run_id}:{},...await He(e),...q?{"Crtr-Approval":q}:{},...m.headers}});_??=Date.now()+(i.commands.timeouts?.requestMs??3e4);let f;try{if(f=await _e(re,{connectMs:i.commands.timeouts?.connectMs,requestMs:i.commands.timeouts?.requestMs,deadlineAt:_,signal:o.signal}),o.signal.aborted)throw o.signal.reason??new Error("provider call aborted")}catch(u){throw o.signal.aborted?o.signal.reason??u:u instanceof Ae?new l("provider_unavailable",u.message,{origin:"provider",details:{status:null,code:u.kind}}):u}if(w??=await Oe({provider:i.id,tool:t.tool,request_id:a,run_id:e.run_id,sub:O,grantee:R,payer:E.payer,ledger_grantee:e.class==="person"?se:R,jti:E.jti,status:f.status,headers:f.headers}),b=f.headers["crtr-responder"],f.status===401&&he(E.key),f.status>=200&&f.status<300){const u=f.body;if(!u||typeof u!="object"||Array.isArray(u))throw new l("provider_bad_response","provider result is not a JSON object",{origin:"provider",details:{status:f.status,message:"provider result is not a JSON object"}});let S;try{S=await Q(e,m,u,{signal:o.signal})}catch($){throw $ instanceof l&&$.code==="provider_error"?new l("provider_bad_response",$.message,{origin:"provider",details:{status:f.status,message:$.message}}):$}h=S.cleanup;const T=U(y.output,S.result);if(T)throw new l("provider_bad_response",`provider result has an invalid output field "${T.field}"`,{origin:"provider",param:T.field,details:{status:f.status,...T}});if(o.signal.aborted)throw o.signal.reason??new Error("provider call aborted");return{status:200,body:S.result}}const I=L(f.body);if(f.status===403&&I.code==="approval_required"&&!q&&!H){H=!0;const u=await ve(e,t,a,I.question,o.signal,Z(i,y),m);if(k=u.questionId,q=u.option,m=await z(e,C,t.arguments,m,{signal:o.signal}),_=void 0,o.signal.aborted)throw new l("user_denied","the approval wait was canceled");continue}if(f.status===403&&I.code==="approval_required"&&q)throw N(f.status,f.body,f.headers,!0);if(f.status!==401&&I.manifest_stale===!0&&!p){p=!0,await pe(i.id,{conditional:!1,...t.version===void 0?{}:{version:t.version}}),i=await B(i.id,t.version);continue}throw N(f.status,f.body,f.headers,!!q)}}catch(i){throw i instanceof l&&i.question_id&&(k=i.question_id),b===void 0&&i instanceof l&&typeof i.responder=="string"&&(b=i.responder),P=`refused:${i instanceof l?i.code:"server_error"}`,await h?.(),i}finally{try{await ke({request_id:a,caller:e,provider:t.provider,tool:t.tool,scope_checked:d,outcome:P,jti:A,receipt_id:w,responder:b,question_id:k})}finally{g()}n.signal.removeEventListener("abort",s)}}v(wr,"callProvider");async function xe(e,r,n,c,t,o){const{machine:s}=o,a=await Me(e,o.sub),j={machine:s,envelope:a,signal:o.signal,deadlineAt:o.deadlineAt,mapFailure:N};if(K(r.major,n.tool)){const p=await Re(j,t.arguments,r.major),m=U(c.output,p);if(m)throw new l("provider_bad_response",`the libraries result has an invalid output field "${m.field}"`,{origin:"provider",param:m.field,details:{status:200,...m}});return{result:p,responder:void 0,cleanup:void 0}}let g=t.arguments,h=null,_="";if(Ce(r.major,n.tool,t.arguments)){const p=await Ie(j,t.arguments,r.major);if(o.deadlineAt-Date.now()<=0)throw V(s,"timeout","");p!==null&&(g=p.arguments,h=p.services,_=p.release)}const d=await qe(s,{tool:n.tool,arguments:g,version:r.major,requestId:o.requestId,runId:e.run_id,deadlineAt:o.deadlineAt,upload:t.upload===null?null:{id:t.upload.upload_id,link:t.upload.upload_link}},a,o.signal);if(o.signal.aborted)throw o.signal.reason??new Error("provider call aborted");if("unreachable"in d)throw V(s,d.unreachable.reason,d.unreachable.message);const A=d.headers["crtr-responder"],w=L(d.body);if(d.status<200||d.status>=300){const p=Ee(s,d.status,typeof w.code=="string"?w.code:void 0,typeof w.message=="string"?w.message:void 0,d.body),m=p===null&&d.status>=500&&typeof w.code=="string"?new l("provider_error",typeof w.message=="string"?w.message:`the device answered HTTP ${d.status}`,{origin:"runtime",status:d.status,details:{code:w.code,status:d.status}}):null;throw Object.assign(p??m??N(d.status,d.body,d.headers),{responder:A})}const b=d.body&&typeof d.body=="object"&&!Array.isArray(d.body)?d.body.result:void 0;if(!b||typeof b!="object"||Array.isArray(b))throw Object.assign(new l("provider_bad_response","the device result is not a JSON object",{origin:"provider",details:{status:d.status,message:"the device result is not a JSON object"}}),{responder:A});let k=b;if(h!==null){const p=Se(k,h);if(Te(s,a,_,p.calls),"error"in p)throw Object.assign(p.error,{responder:A});k=p.result}let P;try{P=await Q(e,t,k,{signal:o.signal})}catch(p){throw p instanceof l&&p.code==="provider_error"?Object.assign(new l("provider_bad_response",p.message,{origin:"provider",details:{status:d.status,message:p.message}}),{responder:A}):p}const i=U(c.output,P.result);if(i)throw await P.cleanup?.(),Object.assign(new l("provider_bad_response",`the device result has an invalid output field "${i.field}"`,{origin:"provider",param:i.field,details:{status:d.status,...i}}),{responder:A});return{result:P.result,responder:A,cleanup:P.cleanup}}v(xe,"callDevice");export{wr as callProvider,He as crtrCallerHeader,N as mapProviderResponse,Oe as onProviderResponse,X as providerLeaves,hr as providerTools};
|
|
1
|
+
var ie=Object.defineProperty;var g=(e,r)=>ie(e,"name",{value:r,configurable:!0});import{validateDeclaredResult as J}from"../../api/command-manifest/result.js";import{callerAllows as ae,requireGroup as se}from"../../daemon/api/handlers/providers.js";import{terminalGrant as de}from"../grants/mirror.js";import{findRefusal as ue,payerOf as le,refusalError as pe,refusedMark as ce,writeCharge as fe}from"../ledger/index.js";import{listInstalledPlugins as me}from"../resolver.js";import{ProviderError as l}from"./errors.js";import{resolveProviderRef as ge}from"./roots.js";import{providerToolPath as ve}from"../plugin-objects-manifest.js";import{ensureProviderBundle as he,refreshProviderBundle as we,resolveProviderBundle as H,unavailableProviderError as ye}from"./bundles.js";import{prepareFileCall as be,resignForRetry as K,resolveFileResult as W}from"./files.js";import{consumeApproval as _e,requireProviderApproval as Ae}from"./approval.js";import{outboundToken as je}from"./mint.js";import{discardFile as ke}from"./token-cache.js";import{registerProviderCall as Pe}from"./inflight.js";import{buildRequestPlan as $e}from"../command-plugins/transport/http-plan.js";import{newTraceId as qe}from"../../shared/traceparent.js";import{sendProviderRequest as Ce,ProviderTransportError as Ee}from"./request.js";import{acceptProviderReceipt as Re}from"./receipts.js";import{writeProviderAudit as Ie}from"./audit.js";import{selectDevice as Te,sendDeviceCall as Me,deviceFailure as Se,deviceUnreachable as X,DEFAULT_DEVICE_REQUEST_MS as Be}from"./device.js";import{isLibsSearch as Y,wantsBundling as Ne,callLibsSearch as Oe,bundleExec as Fe,mapLibOutcome as De,reportLibCalls as Ue}from"./device-libs.js";import{directoryIssuer as Le,ownMachineId as Je}from"../peer/directory.js";import{formatCrtrCaller as Z}from"../command-plugins/caller-header.js";import{getNode as He}from"../canvas/canvas.js";import{envelopeForProviderCaller as Ge}from"../peer/envelope.js";const xe="app:terminal";function ee(e){const r=[],i=g((c,t,n)=>{const a=[...t,c.name],s=n||c.tier==="hidden";if(c.kind==="branch"){for(const v of c.children)i(v,a,s);return}const j=ve(e.roots.length,a);r.push({tool:j,leaf:c,hidden:s})},"walk");for(const c of e.roots)i(c,[],!1);return r}g(ee,"providerLeaves");function re(e){if(e.kind!=="branch")return null;const r=[];for(const h of e.children)if(h.kind==="branch"){const _=re(h);_&&r.push(_)}else if("group"in h&&h.group){const{kind:_,name:d,description:A,whenToUse:w,tier:y,summary:k,params:P,output:o,effects:p,group:m}=h;r.push({kind:_,name:d,description:A,whenToUse:w,...y===void 0?{}:{tier:y},summary:k,params:P,output:o,effects:p,group:m})}if(r.length===0)return null;const{kind:i,name:c,description:t,whenToUse:n,tier:a,summary:s,model:j,rootEntry:v}=e;return{kind:i,name:c,description:t,whenToUse:n,...a===void 0?{}:{tier:a},summary:s,...j===void 0?{}:{model:j},...v===void 0?{}:{rootEntry:v},children:r}}g(re,"providerHelpBranch");async function Pr(e,r){const i=await H(r),c=ee(i.commands),t=me("user").find(n=>n.name===r)?.manifest.description??r;return{provider:r,status:"available",major:i.major,display_name:t,transport:i.transport.kind,groups:i.provider.groups.filter(n=>ae(e,`${r}:${n.group}`)).map(n=>({group:n.group,leaves:c.filter(({leaf:a,hidden:s})=>!s&&a.group===n.group).map(({tool:a,leaf:s})=>({tool:a,description:s.description,summary:s.summary,params:s.params,output:s.output}))})),commands:i.commands.roots.flatMap(n=>{const a=re(n);return a?[a]:[]})}}g(Pr,"providerTools");async function ze(e){return await Re(e.headers["crtr-receipt"],e)}g(ze,"onProviderResponse");async function Qe(e){if(e.class==="person"){const r=(await de())?.sub;if(!r)throw new l("grant_revoked","This machine has no active Northlight grant for your terminal. Run `crtr sys join` again from /account/machines.");return{sub:r,grantee:r}}if(!e.sub||!e.grantee)throw new l("grant_revoked","the caller has no active grant");return{sub:e.sub,grantee:e.grantee}}g(Qe,"identity");function Ve(e,r){return[`${e.id}:${r.group}`]}g(Ve,"callScope");function Ke(e,r){const i=ee(e.commands).find(c=>c.tool===r);if(!i)throw new l("not_found",`tool "${r}" is not in provider "${e.id}"`,{param:"tool"});if(!i.leaf.group)throw new l("not_found",`tool "${r}" has no group`,{param:"tool"});return i.leaf}g(Ke,"leafFor");function G(e){if(!e||typeof e!="object"||Array.isArray(e))return{};const r=e.error;return!r||typeof r!="object"||Array.isArray(r)?{}:r}g(G,"errorBody");function We(e){const r=Array.isArray(e)?e[0]:e;if(!r)return;const i=Number(r);if(Number.isFinite(i)&&i>=0)return i;const c=Date.parse(r);return Number.isFinite(c)?Math.max(0,Math.ceil((c-Date.now())/1e3)):void 0}g(We,"retryAfter");function N(e,r,i,c=!1){const t=G(r),n=typeof t.code=="string"?t.code:void 0,a=typeof t.message=="string"?t.message:`provider answered HTTP ${e}`,s=typeof t.field=="string"?t.field:void 0,v={origin:"provider",details:{code:n??null,message:a,...s?{field:s}:{},...typeof t.next=="string"?{next:t.next}:{},...t.received!==void 0?{received:t.received}:{},status:e},...s?{param:s}:{}};return e===429?new l("provider_rate_limited",a,{...v,retry_after_s:We(i["retry-after"])}):e===401||e>=500?new l("provider_unavailable",a,v):e===403&&n==="provider_refused"?new l("provider_refused",a,v):e===403&&n==="approval_required"?new l("provider_error",c?"provider asked for approval again":"provider approval question is invalid",{...v,status:e}):new l("provider_error",a,{...v,status:e})}g(N,"mapProviderResponse");function te(e,r){return JSON.stringify({major:e.major,endpoint:e.transport.kind==="http"?e.transport.endpoint:null,baseUrl:e.commands.baseUrl??null,rest:r.rest,params:r.params,output:r.output})}g(te,"approvalShape");async function Xe(e){const r=e.origin!==void 0?Z({node:e.origin.node??void 0,run:e.origin.run??void 0,machine:e.origin.machine}):Z({node:e.node_id??void 0,run:e.run_id??void 0,profile:e.node_id?(await He(e.node_id))?.profile_id??void 0:void 0,machine:Le()!==null?Je():void 0});return r===""?{}:{"Crtr-Caller":r}}g(Xe,"crtrCallerHeader");async function $r(e,r,i){const c=ge(r.provider);if(c===null)throw new l("not_found",`provider "${r.provider}" is not available`,{param:"provider"});const t={...r,provider:c},n=new AbortController,a=g(()=>n.abort(i.signal.reason),"abort");i.signal.aborted?a():i.signal.addEventListener("abort",a,{once:!0});let s=i.requestId;const j=i.traceId??qe(),v=Pe({request_id:s,run_id:e.run_id,node_id:e.node_id,controller:n});let h,_,d,A,w,y,k,P="allowed";try{try{await he(t.provider)}catch{throw ye(t.provider)}let o=await H(t.provider,t.version),p=!1,m,O,$,x=!1,z=!1,F,Q=0;for(;;){const b=Ke(o,t.tool);if(d=`${o.id}:${b.group}`,se(e,o.id,b.group),o.transport.kind!=="machine"&&t.machine!==void 0)throw new l("invalid_argument",`provider "${o.id}" is not served by a device, so it takes no machine`,{param:"machine"});o.transport.kind==="machine"&&F===void 0&&(F=await Te(t.machine,void 0,{newest:Y(o.major,t.tool)}),Q=Date.now()+(o.commands.timeouts?.requestMs??Be));let D=null;if(t.approval&&!x){const u=await _e(e,t,te(o,b));$=u.option,D=u.prepared,k=t.approval,s=u.requestId,x=!0}const I={params:b.params.filter(u=>"type"in u&&u.type==="file").map(u=>u.name),output:b.output.find(u=>u.type==="file")?.name??null},V=JSON.stringify(I);if(O!==void 0&&O!==V)throw new l("provider_bad_response","the refreshed manifest changed the tool file contract",{origin:"provider",details:{status:409,message:"manifest_stale changed the tool file contract"}});O=V,D&&(m=await K(e,I,t.arguments,D,{signal:n.signal})),m??=await be(e,I,t.arguments,{signal:n.signal});const{sub:q,grantee:T}=await Qe(e);if(o.transport.kind==="machine"){const u=await Ye(e,o,t,b,m,{sub:q,requestId:s,deadlineAt:Q,signal:n.signal,machine:F});return y=u.responder,h=u.cleanup,{status:200,body:u.result}}const C=await je({audience:o.transport.endpoint,sub:q,grantee:T,initiating_app:T,scope:Ve(o,b)},{signal:n.signal});A=C.jti;const U=e.class==="person"?xe:T,E=le({call:"tool",tokenPayer:C.payer,sub:q}),L=await ue({scope:"call",payer:E.payer,funding:E.funding,sub:q,grantee:U,provider:`app:${o.id}`});if(L!==null)throw await fe({request:s,kind:"tool",what:`${o.id}:${t.tool}`,usd:0,payer:E.payer,funding:E.funding,sub:q,grantee:U,node:e.node_id,run:e.run_id,provider:`app:${o.id}`,causedBy:i.causedBy??null,refused:ce(L)}),pe(L);const oe={registration:{name:o.id,endpoint:o.transport.endpoint},...o.commands.baseUrl?{baseUrl:o.commands.baseUrl}:{},...o.commands.timeouts?{timeouts:o.commands.timeouts}:{},params:b.params,rest:b.rest,output:b.output,commandPath:[o.id,...t.tool.split(" ")]},ne=$e(oe,m.arguments,void 0,{authorization:`Bearer ${C.access_token}`,requestId:s,traceId:j,fileMode:"pass-through",extraHeaders:{...i.causedBy?{"Crtr-Caused-By":i.causedBy}:{},...e.run_id?{"Crtr-Run-Id":e.run_id}:{},...await Xe(e),...$?{"Crtr-Approval":$}:{},...m.headers}});_??=Date.now()+(o.commands.timeouts?.requestMs??3e4);let f;try{if(f=await Ce(ne,{connectMs:o.commands.timeouts?.connectMs,requestMs:o.commands.timeouts?.requestMs,deadlineAt:_,signal:n.signal}),n.signal.aborted)throw n.signal.reason??new Error("provider call aborted")}catch(u){throw n.signal.aborted?n.signal.reason??u:u instanceof Ee?new l("provider_unavailable",u.message,{origin:"provider",details:{status:null,code:u.kind}}):u}if(w??=await ze({provider:o.id,tool:t.tool,request_id:s,run_id:e.run_id,sub:q,grantee:T,payer:C.payer,ledger_grantee:U,funding:E.funding,node_id:e.node_id,caused_by:i.causedBy??null,jti:C.jti,status:f.status,headers:f.headers}),y=f.headers["crtr-responder"],f.status===401&&ke(C.key),f.status>=200&&f.status<300){const u=f.body;if(!u||typeof u!="object"||Array.isArray(u))throw new l("provider_bad_response","provider result is not a JSON object",{origin:"provider",details:{status:f.status,message:"provider result is not a JSON object"}});let S;try{S=await W(e,m,u,{signal:n.signal})}catch(R){throw R instanceof l&&R.code==="provider_error"?new l("provider_bad_response",R.message,{origin:"provider",details:{status:f.status,message:R.message}}):R}h=S.cleanup;const B=J(b.output,S.result);if(B)throw new l("provider_bad_response",`provider result has an invalid output field "${B.field}"`,{origin:"provider",param:B.field,details:{status:f.status,...B}});if(n.signal.aborted)throw n.signal.reason??new Error("provider call aborted");return{status:200,body:S.result}}const M=G(f.body);if(f.status===403&&M.code==="approval_required"&&!$&&!z){z=!0;const u=await Ae(e,t,s,M.question,n.signal,te(o,b),m);if(k=u.questionId,$=u.option,m=await K(e,I,t.arguments,m,{signal:n.signal}),_=void 0,n.signal.aborted)throw new l("user_denied","the approval wait was canceled");continue}if(f.status===403&&M.code==="approval_required"&&$)throw N(f.status,f.body,f.headers,!0);if(f.status!==401&&M.manifest_stale===!0&&!p){p=!0,await we(o.id,{conditional:!1,...t.version===void 0?{}:{version:t.version}}),o=await H(o.id,t.version);continue}throw N(f.status,f.body,f.headers,!!$)}}catch(o){throw o instanceof l&&o.question_id&&(k=o.question_id),y===void 0&&o instanceof l&&typeof o.responder=="string"&&(y=o.responder),P=`refused:${o instanceof l?o.code:"server_error"}`,await h?.(),o}finally{try{await Ie({request_id:s,caller:e,provider:t.provider,tool:t.tool,scope_checked:d,outcome:P,jti:A,receipt_id:w,responder:y,question_id:k})}finally{v()}i.signal.removeEventListener("abort",a)}}g($r,"callProvider");async function Ye(e,r,i,c,t,n){const{machine:a}=n,s=await Ge(e,n.sub),j={machine:a,envelope:s,signal:n.signal,deadlineAt:n.deadlineAt,mapFailure:N};if(Y(r.major,i.tool)){const p=await Oe(j,t.arguments,r.major),m=J(c.output,p);if(m)throw new l("provider_bad_response",`the libraries result has an invalid output field "${m.field}"`,{origin:"provider",param:m.field,details:{status:200,...m}});return{result:p,responder:void 0,cleanup:void 0}}let v=t.arguments,h=null,_="";if(Ne(r.major,i.tool,t.arguments)){const p=await Fe(j,t.arguments,r.major);if(n.deadlineAt-Date.now()<=0)throw X(a,"timeout","");p!==null&&(v=p.arguments,h=p.services,_=p.release)}const d=await Me(a,{tool:i.tool,arguments:v,version:r.major,requestId:n.requestId,runId:e.run_id,deadlineAt:n.deadlineAt,upload:t.upload===null?null:{id:t.upload.upload_id,link:t.upload.upload_link}},s,n.signal);if(n.signal.aborted)throw n.signal.reason??new Error("provider call aborted");if("unreachable"in d)throw X(a,d.unreachable.reason,d.unreachable.message);const A=d.headers["crtr-responder"],w=G(d.body);if(d.status<200||d.status>=300){const p=Se(a,d.status,typeof w.code=="string"?w.code:void 0,typeof w.message=="string"?w.message:void 0,d.body),m=p===null&&d.status>=500&&typeof w.code=="string"?new l("provider_error",typeof w.message=="string"?w.message:`the device answered HTTP ${d.status}`,{origin:"runtime",status:d.status,details:{code:w.code,status:d.status}}):null;throw Object.assign(p??m??N(d.status,d.body,d.headers),{responder:A})}const y=d.body&&typeof d.body=="object"&&!Array.isArray(d.body)?d.body.result:void 0;if(!y||typeof y!="object"||Array.isArray(y))throw Object.assign(new l("provider_bad_response","the device result is not a JSON object",{origin:"provider",details:{status:d.status,message:"the device result is not a JSON object"}}),{responder:A});let k=y;if(h!==null){const p=De(k,h);if(Ue(a,s,_,p.calls),"error"in p)throw Object.assign(p.error,{responder:A});k=p.result}let P;try{P=await W(e,t,k,{signal:n.signal})}catch(p){throw p instanceof l&&p.code==="provider_error"?Object.assign(new l("provider_bad_response",p.message,{origin:"provider",details:{status:d.status,message:p.message}}),{responder:A}):p}const o=J(c.output,P.result);if(o)throw await P.cleanup?.(),Object.assign(new l("provider_bad_response",`the device result has an invalid output field "${o.field}"`,{origin:"provider",param:o.field,details:{status:d.status,...o}}),{responder:A});return{result:P.result,responder:A,cleanup:P.cleanup}}g(Ye,"callDevice");export{$r as callProvider,Xe as crtrCallerHeader,N as mapProviderResponse,ze as onProviderResponse,ee as providerLeaves,Pr as providerTools};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var g=Object.defineProperty;var d=(t,i)=>g(t,"name",{value:i,configurable:!0});import{RunError as _}from"../runs/operations.js";import{errorCodes as r}from"../../api/error-codes.js";const b={provider_error:{type:"invalid_request_error",status:400,retryable:!1},provider_rate_limited:r.provider_rate_limited,provider_unavailable:r.provider_unavailable,provider_refused:r.provider_refused,provider_not_connected:r.provider_not_connected,provider_version_retired:r.provider_version_retired,storage_unavailable:r.storage_unavailable,approval_pending:{...r.approval_pending,user_action:"answer_question"},user_denied:r.user_denied},q={unauthorized:r.unauthorized,grant_revoked:r.grant_revoked,machine_revoked:r.machine_revoked,scope_missing:r.scope_missing,permission_error:r.permission_error,invalid_request:r.invalid_request,not_found:r.not_found,not_implemented:r.not_implemented,runtime_starting:r.runtime_starting,server_error:r.server_error,provider_bad_response:r.provider_bad_response,invalid_argument:r.invalid_argument,machine_required:r.machine_required,device_offline:r.device_offline,device_timeout:r.device_timeout,device_disconnected:r.device_disconnected,peer_version_too_old:r.peer_version_too_old,outcome_unknown:{type:"invalid_request_error",status:409,retryable:!1},wrong_site:{type:"invalid_request_error",status:409,retryable:!1},site_signed_out:{type:"invalid_request_error",status:409,retryable:!1},js_exception:{type:"invalid_request_error",status:409,retryable:!1},lib_broken:{type:"server_error",status:502,retryable:!1}};function a(t,i){return b[t]??q[t]??(Object.prototype.hasOwnProperty.call(r,t)?r[t]:void 0)??{type:i===401?"authentication_error":i===403?"permission_error":i===429?"rate_limit_error":i>=500?"server_error":"invalid_request_error",status:i,retryable:i>=500}}d(a,"codeRow");class u extends _{static{d(this,"ProviderError")}origin;type;retry_after_s;question_id;user_action;run_id;constructor(i,o,n={}){const e=a(i,n.status??500);super(n.status??e.status,i,o,n.param,n.details,n.scope,e.retryable),this.type=e.type,this.origin=n.origin??"runtime",n.cause!==void 0&&(this.cause=n.cause),n.retry_after_s!==void 0&&(this.retry_after_s=n.retry_after_s),n.question_id!==void 0&&(this.question_id=n.question_id),n.run_id!==void 0&&(this.run_id=n.run_id),e.user_action!==void 0&&(this.user_action=e.user_action)}}function w(t){return new u("scope_missing",`missing scope ${t}`,{scope:t})}d(w,"scopeMissing");function h(t){if(!(t instanceof Error))return null;const{status:i,code:o,details:n,retryable:e}=t;return typeof i!="number"||typeof o!="string"||i<400||i>599?null:new _(i,o,t.message,void 0,n,void 0,typeof e=="boolean"?e:a(o,i).retryable)}d(h,"shaped");function x(t){if(t.code==="unauthorized"||t.code==="grant_revoked")return"reconnect";if(t.code==="scope_missing"&&t.scope)return`grant_scope:${t.scope}`}d(x,"directoryAction");function O(t,i,o,n){const e=t instanceof _?t:h(t)??new u("server_error","provider request failed"),s=e instanceof u?e:null,y=a(e.code,e.status),c=s?.run_id??n,p=e.details?.user_action,l=s?.user_action??(e.code==="cap_exhausted"?typeof p=="string"?p:void 0:o?x(e):void 0),f=e.code==="cap_exhausted"?e.details?.reset_at:void 0,m={code:e.code,message:e.message,...e.details===void 0?{}:{details:e.details},type:s?.type??y.type,...e.param?{param:e.param}:{},origin:s?.origin??"runtime",retryable:e.retryable,...s?.retry_after_s===void 0?{}:{retry_after_s:s.retry_after_s},...typeof f=="string"?{reset_at:f}:{},request_id:i,...c?{run_id:c}:{},...s?.question_id?{question_id:s.question_id}:{},...l?{user_action:l}:{},...e.scope?{scope:e.scope}:{}},v={"Request-Id":i};return s?.retry_after_s!==void 0&&(v["Retry-After"]=String(s.retry_after_s)),{status:e.status,body:{error:m},headers:v}}d(O,"providerErrorBody");export{b as PROVIDER_CODES,u as ProviderError,a as codeRow,O as providerErrorBody,w as scopeMissing};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Funding } from '../ledger/types.js';
|
|
1
2
|
type ReceiptCall = {
|
|
2
3
|
provider: string;
|
|
3
4
|
tool: string;
|
|
@@ -7,8 +8,13 @@ type ReceiptCall = {
|
|
|
7
8
|
run_id: string | null;
|
|
8
9
|
/** The outbound token's `payer` claim: the principal the directory charges (an app, or the user). */
|
|
9
10
|
payer: string;
|
|
10
|
-
/**
|
|
11
|
+
/** The app the charge is attributed to when it differs from the receipt's grantee (the person's calls count under `app:terminal`). */
|
|
11
12
|
ledger_grantee?: string;
|
|
13
|
+
/** `bill` or `endpoint`, from `payerOf` on the token's payer. */
|
|
14
|
+
funding: Funding;
|
|
15
|
+
/** The calling node and the call's `Crtr-Caused-By`; null when none. */
|
|
16
|
+
node_id: string | null;
|
|
17
|
+
caused_by: string | null;
|
|
12
18
|
};
|
|
13
19
|
/**
|
|
14
20
|
* A provider's informational receipts must belong to the call that carried them. The header is one
|
|
@@ -1,3 +1 @@
|
|
|
1
|
-
var
|
|
2
|
-
(provider, receipt_id, grantee, run_id, usd_equivalent, received_at) VALUES (?, ?, ?, ?, ?, ?)
|
|
3
|
-
ON CONFLICT DO NOTHING`).run(r.provider,s.receipt_id,r.grantee,r.run_id,s.usd_equivalent,new Date().toISOString())).changes||(await f(i,{grantee:r.ledger_grantee??r.grantee,payer:r.payer.startsWith("app:")?"app":"user",source:`provider:${r.provider}`,served_model:"",input_tokens:0,output_tokens:0,cached_tokens:0,usd_equivalent:s.usd_equivalent}),!r.run_id))continue;const d=await i.prepare("SELECT usage_json FROM nodes WHERE node_id = ? AND run_id = ?").get(r.run_id,r.run_id);if(!d)continue;const u=d.usage_json?JSON.parse(d.usage_json):{};u.cost_usd=(typeof u.cost_usd=="number"?u.cost_usd:0)+s.usd_equivalent,await i.prepare("UPDATE nodes SET usage_json = ? WHERE node_id = ?").run(JSON.stringify(u),r.run_id)}}),o[0].receipt_id}a(N,"acceptProviderReceipt");export{N as acceptProviderReceipt};
|
|
1
|
+
var a=Object.defineProperty;var p=(t,e)=>a(t,"name",{value:e,configurable:!0});import{withCanvasWrite as f}from"../canvas/db.js";import{receiptChargeId as g,writeCharge as y}from"../ledger/index.js";const A=8,E=65536;function b(t,e){if(!t||typeof t!="object"||Array.isArray(t))return!1;const r=t;return typeof r.receipt_id=="string"&&!!r.receipt_id&&r.receipt_id.length<=256&&r.provider===`app:${e.provider}`&&r.tool===e.tool&&r.request_id===e.request_id&&r.sub===e.sub&&r.grantee===e.grantee&&r.payer===e.payer&&(r.run_id??null)===e.run_id&&typeof r.unit=="string"&&!!r.unit&&typeof r.units=="number"&&Number.isFinite(r.units)&&r.units>=0&&typeof r.time=="string"&&Number.isFinite(Date.parse(r.time))&&typeof r.usd_equivalent=="number"&&Number.isFinite(r.usd_equivalent)&&r.usd_equivalent>=0}p(b,"belongsToCall");async function h(t,e){const r=Array.isArray(t)?t[0]:t;if(!r||r.length>E)return;let n;try{n=JSON.parse(r)}catch{return}if(Array.isArray(n)&&n.length>A)return;const o=(Array.isArray(n)?n:[n]).filter(u=>b(u,e));if(o.length)return await f(async u=>{for(const i of o){const{written:_}=await y({id:g(e.provider,i.receipt_id),request:e.request_id,kind:"tool",what:`${e.provider}:${e.tool}`,units:{units:i.units,unit:i.unit},usd:i.usd_equivalent,payer:e.payer,funding:e.funding,sub:e.sub,grantee:e.ledger_grantee??e.grantee,node:e.node_id,run:e.run_id,provider:`app:${e.provider}`,causedBy:e.caused_by,vendorRef:i.receipt_id});if(!_||!e.run_id)continue;const d=await u.prepare("SELECT usage_json FROM nodes WHERE node_id = ? AND run_id = ?").get(e.run_id,e.run_id);if(!d)continue;const s=d.usage_json?JSON.parse(d.usage_json):{};s.cost_usd=(typeof s.cost_usd=="number"?s.cost_usd:0)+i.usd_equivalent,await u.prepare("UPDATE nodes SET usage_json = ? WHERE node_id = ?").run(JSON.stringify(s),e.run_id)}}),o[0].receipt_id}p(h,"acceptProviderReceipt");export{h as acceptProviderReceipt};
|
|
@@ -46,6 +46,7 @@ export declare function startRun(principal: AppPrincipal, input: {
|
|
|
46
46
|
deadline?: string;
|
|
47
47
|
output_schema?: Record<string, unknown>;
|
|
48
48
|
message?: string;
|
|
49
|
+
causedBy?: string;
|
|
49
50
|
}, idempotencyKey?: string, resolveAttachments?: AttachmentResolver): Promise<Record<string, unknown>>;
|
|
50
51
|
export declare function listRuns(grantee: string | null, options: {
|
|
51
52
|
status?: string;
|