@spendgraph/prompt 0.8.2 → 0.9.1

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/client.js CHANGED
@@ -1 +1 @@
1
- import{Spendgraph as h}from"@spendgraph/sdk";import{Budget as p}from"./budget/index.js";import{buildCustomPrompt as m}from"./build/index.js";import{PullCache as f}from"./cache/index.js";import{makePrompt as k}from"./prompt/index.js";import{pullWithCache as y}from"./pull/index.js";import{newRolloutId as i}from"./run/id.js";import{runAcrossModels as b,runOnce as w,sampleRuns as g}from"./run/index.js";const E=4;function a(o,r){const e=o?.prompt;if(!e||typeof e!="object"||typeof e.id!="string")throw new Error(`Asked for prompt "${r}" and the response carried no prompt. Check the base URL points at a spendgraph app and that the key can read this project.`);return e}class v{sdk;cache;hasKey;onReportError;concurrency;budget;warnedAboutTokens=!1;constructor(r){const{cache:e,onReportError:t,onPullError:s,concurrency:c,maxCostMicros:u,...d}=r;this.sdk=new h(d),this.cache=new f({...e,onRefreshError:e?.onRefreshError??s,identify:n=>[n.id,n.slug].filter(l=>!!l)}),this.hasKey=!!r.apiKey,this.onReportError=t,this.concurrency=Math.max(1,c??E),this.budget=new p("maxCostMicros"in r?u:void 0)}recorder(){return{enabled:!0,write:(r,e)=>(this.warnOnEmptyTokens(e),this.priced(r,e))}}async pull(r){const e=await y(this.cache,r,async()=>{const t=await this.sdk.prompts.get(r);return a(t,r)});return k({id:e.id,name:e.name??e.id,slug:e.slug??null,blocks:e.blocks??[],question:e.question??"",fields:e.fieldSpec??[],versionId:e.currentVersionId??null,models:e.models??[]},"server",this.recorder())}async create(r,e){const t=await this.sdk.prompts.create({projectId:e,name:r.name,...r.blocks?{blocks:r.blocks}:{},...r.question===void 0?{}:{question:r.question},...r.variables?{variables:r.variables}:{},...r.models?{models:r.models}:{}}),s=a(t,r.name);return this.pull(s.id)}build(r,e={}){return m(r,{onReportError:this.onReportError,...e,sdk:this.sdk})}warnOnEmptyTokens(r){this.warnedAboutTokens||r.status!=="failed"&&((r.inputTokens??0)>0||(r.outputTokens??0)>0||(this.warnedAboutTokens=!0,console.warn("[prompt] call() recorded a rollout with no tokens. This package never sees the provider response, so return inputTokens and outputTokens from your callback or every cost on this prompt reads as zero.")))}async run(r,e={},t={}){return w(this.sdk.prompts,r,e,t,this.budget)}async sample(r,e={},t={}){return g(this.sdk.prompts,r,e,{concurrency:this.concurrency,...t},this.budget)}async runAll(r,e={},t={}){const s=t.models??(await this.pull(r)).models;if(s.length===0)throw new Error("No models given and the prompt has none saved.");return b(this.sdk.prompts,r,e,s,{concurrency:this.concurrency,...t},this.budget)}async cases(r){return this.sdk.prompts.cases(r)}async setCases(r,e){return this.sdk.prompts.putCases(r,e)}spent(){return this.budget.spent()}remaining(){return this.budget.remaining()}async versions(r,e={}){return this.sdk.prompts.versions(r,e)}async promote(r,e){const t=await this.sdk.prompts.promote(r,e);return this.invalidate(r),t}invalidate(r){if(!r){this.cache.clear();return}for(const e of this.cache.keysWhere(t=>t.id===r||t.slug===r))this.cache.delete(e);this.cache.delete(r),this.cache.invalidate(r)}async priced(r,e){const t=e.rolloutId??i();if(this.hasKey)try{const s=await this.sdk.prompts.report(r,{...e,rolloutId:t});return s.priced===!1?void 0:s.rollout?.costMicros}catch(s){this.onReportError?.(s);return}}async report(r,e){const t=e.rolloutId??i();if(!this.hasKey)return t;try{await this.sdk.prompts.report(r,{...e,rolloutId:t})}catch(s){this.onReportError?.(s)}return t}}function M(o,r){return new v(r).pull(o)}export{v as PromptClient,M as pullPrompt};
1
+ import{Spendgraph as h}from"@spendgraph/sdk";import{Budget as p}from"./budget/index.js";import{buildCustomPrompt as m}from"./build/index.js";import{PullCache as f}from"./cache/index.js";import{makePrompt as k}from"./prompt/index.js";import{pullWithCache as y}from"./pull/index.js";import{newRolloutId as i}from"./run/id.js";import{runAcrossModels as b,runOnce as w,sampleRuns as g}from"./run/index.js";import{PROMPT_VERSION as E}from"./version.js";const R=4;function a(o,r){const e=o?.prompt;if(!e||typeof e!="object"||typeof e.id!="string")throw new Error(`Asked for prompt "${r}" and the response carried no prompt. Check the base URL points at a spendgraph app and that the key can read this project.`);return e}class v{sdk;cache;hasKey;onReportError;concurrency;budget;warnedAboutTokens=!1;constructor(r){const{cache:e,onReportError:t,onPullError:s,concurrency:c,maxCostMicros:u,...d}=r;this.sdk=new h({...d,sentBy:`prompt/${E}`}),this.cache=new f({...e,onRefreshError:e?.onRefreshError??s,identify:n=>[n.id,n.slug].filter(l=>!!l)}),this.hasKey=!!r.apiKey,this.onReportError=t,this.concurrency=Math.max(1,c??R),this.budget=new p("maxCostMicros"in r?u:void 0)}recorder(){return{enabled:!0,write:(r,e)=>(this.warnOnEmptyTokens(e),this.priced(r,e))}}async pull(r){const e=await y(this.cache,r,async()=>{const t=await this.sdk.prompts.get(r);return a(t,r)});return k({id:e.id,name:e.name??e.id,slug:e.slug??null,blocks:e.blocks??[],question:e.question??"",fields:e.fieldSpec??[],versionId:e.currentVersionId??null,models:e.models??[]},"server",this.recorder())}async create(r,e){const t=await this.sdk.prompts.create({projectId:e,name:r.name,...r.blocks?{blocks:r.blocks}:{},...r.question===void 0?{}:{question:r.question},...r.variables?{variables:r.variables}:{},...r.models?{models:r.models}:{}}),s=a(t,r.name);return this.pull(s.id)}build(r,e={}){return m(r,{onReportError:this.onReportError,...e,sdk:this.sdk})}warnOnEmptyTokens(r){this.warnedAboutTokens||r.status!=="failed"&&((r.inputTokens??0)>0||(r.outputTokens??0)>0||(this.warnedAboutTokens=!0,console.warn("[prompt] call() recorded a rollout with no tokens. This package never sees the provider response, so return inputTokens and outputTokens from your callback or every cost on this prompt reads as zero.")))}async run(r,e={},t={}){return w(this.sdk.prompts,r,e,t,this.budget)}async sample(r,e={},t={}){return g(this.sdk.prompts,r,e,{concurrency:this.concurrency,...t},this.budget)}async runAll(r,e={},t={}){const s=t.models??(await this.pull(r)).models;if(s.length===0)throw new Error("No models given and the prompt has none saved.");return b(this.sdk.prompts,r,e,s,{concurrency:this.concurrency,...t},this.budget)}async cases(r){return this.sdk.prompts.cases(r)}async setCases(r,e){return this.sdk.prompts.putCases(r,e)}spent(){return this.budget.spent()}remaining(){return this.budget.remaining()}async versions(r,e={}){return this.sdk.prompts.versions(r,e)}async promote(r,e){const t=await this.sdk.prompts.promote(r,e);return this.invalidate(r),t}invalidate(r){if(!r){this.cache.clear();return}for(const e of this.cache.keysWhere(t=>t.id===r||t.slug===r))this.cache.delete(e);this.cache.delete(r),this.cache.invalidate(r)}async priced(r,e){const t=e.rolloutId??i();if(this.hasKey)try{const s=await this.sdk.prompts.report(r,{...e,rolloutId:t});return s.priced===!1?void 0:s.rollout?.costMicros}catch(s){this.onReportError?.(s);return}}async report(r,e){const t=e.rolloutId??i();if(!this.hasKey)return t;try{await this.sdk.prompts.report(r,{...e,rolloutId:t})}catch(s){this.onReportError?.(s)}return t}}function B(o,r){return new v(r).pull(o)}export{v as PromptClient,B as pullPrompt};
@@ -1 +1 @@
1
- import{serializeFields as R}from"@spendgraph/sdk";import{fingerprint as S}from"../fingerprint/index.js";import{findVariables as v,renderMessages as h}from"../render/index.js";import{recordable as E}from"../render/record.js";import{newRolloutId as $}from"../run/id.js";import{bind as j}from"./bind.js";const x={enabled:!1,write:()=>{}},A=50;let D=!1;function z(e){D||e.length<=A||(D=!0,console.warn(`[prompt] ${e.length} messages is over the ${A} a rollout can record. The call still runs; the rollout will be rejected. Trim the history you pass.`))}function O(e,r,l){const s=Object.keys(e).filter(i=>l.has(i)&&!r.has(i));return s.length===0||console.warn(`[prompt] ${s.map(i=>`{${i}}`).join(", ")} appears in this prompt and you passed a value for it, but no field declares it, so it was not substituted and the placeholder goes to the model as written. Add it to the prompt's fields.`),s}function P(e){for(let r=e.length-1;r>=0;r--)if(e[r].role==="user")return e[r].content;return""}function L(e,r,l=x){const s=new Set(e.fields.map(t=>t.name)),i=new Set(v(e.blocks,e.question));let w=!1;const u=(t={})=>(w||(w=O(t,s,i).length>0),R(t,e.fields)),q=(t={},f={})=>h(e.blocks,e.question,u(t),f.history),b={id:e.id,name:e.name,slug:e.slug,fields:e.fields,versionId:e.versionId,fingerprint:S({name:e.name,blocks:e.blocks,question:e.question}),models:e.models,source:r,serialize:u,format:q,async call(t,f,d={}){const k=u(t),a=h(e.blocks,e.question,k,d.history);z(a);const m=d.tools?.trace(d.query??P(a)),T=d.rolloutId??$(),g=l.enabled&&(d.report??!0),y=Date.now(),I=()=>({rolloutId:T,versionId:e.versionId,fields:k,rendered:E(a)});let o;try{o=await f({messages:a,turn:m})}catch(n){if(g){const c=m?.record();l.write(e.id,{...I(),model:"unknown",output:"",status:"failed",error:n instanceof Error?n.message:String(n),latencyMs:Date.now()-y,offeredTools:c?.offeredTools,steps:c?.steps})}throw n}const M=Date.now()-y;let p;if(g){const n=m?.record(),c=l.write(e.id,{...I(),model:o.model,output:o.output,status:o.status??"completed",error:o.error,inputTokens:o.inputTokens,outputTokens:o.outputTokens,cacheReadTokens:o.cacheReadTokens,cacheWriteTokens:o.cacheWriteTokens,citationTokens:o.citationTokens,reasoningTokens:o.reasoningTokens,latencyMs:M,caseId:o.caseId,seed:o.seed,offeredTools:o.offeredTools??n?.offeredTools,steps:o.steps??n?.steps});p=c instanceof Promise?c:void 0}return{...o,rolloutId:T,...p?{pricing:p}:{}}},bind:t=>j(b,t)};return b}export{A as MAX_RECORDED_MESSAGES,L as makePrompt,x as noRecorder};
1
+ import{serializeFields as S}from"@spendgraph/sdk";import{fingerprint as q}from"../fingerprint/index.js";import{findVariables as N,renderMessages as h}from"../render/index.js";import{recordable as O}from"../render/record.js";import{newRolloutId as j}from"../run/id.js";import{bind as v}from"./bind.js";const W={enabled:!1,write:()=>{}},D=50;let E=!1;function _(e){E||e.length<=D||(E=!0,console.warn(`[prompt] ${e.length} messages is over the ${D} a rollout can record. The call still runs; the rollout will be rejected. Trim the history you pass.`))}function $(e,t,n){const s=Object.keys(e).filter(i=>n.has(i)&&!t.has(i));return s.length===0||console.warn(`[prompt] ${s.map(i=>`{${i}}`).join(", ")} appears in this prompt and you passed a value for it, but no field declares it, so it was not substituted and the placeholder goes to the model as written. Add it to the prompt's fields.`),s}const x=["inputTokens","outputTokens","cacheReadTokens","cacheWriteTokens","citationTokens","reasoningTokens"],A={model:"unknown"};function K(e){return Number.isInteger(e)&&e>=0}function U(e){const t=e instanceof Error?e.reply:void 0;if(typeof t!="object"||t===null)return A;const n=t;if(typeof n.model!="string"||n.model==="")return A;const s={model:n.model};for(const i of x){const l=n[i];K(l)&&(s[i]=l)}return s}function z(e){for(let t=e.length-1;t>=0;t--)if(e[t].role==="user")return e[t].content;return""}function V(e,t,n=W){const s=new Set(e.fields.map(r=>r.name)),i=new Set(N(e.blocks,e.question));let l=!1;const f=(r={})=>(l||(l=$(r,s,i).length>0),S(r,e.fields)),M=(r={},m={})=>h(e.blocks,e.question,f(r),m.history),T={id:e.id,name:e.name,slug:e.slug,fields:e.fields,versionId:e.versionId,fingerprint:q({name:e.name,blocks:e.blocks,question:e.question}),models:e.models,source:t,serialize:f,format:M,async call(r,m,d={}){const b=f(r),a=h(e.blocks,e.question,b,d.history);_(a);const p=d.tools?.trace(d.query??z(a)),w=d.rolloutId??j(),g=n.enabled&&(d.report??!0),y=Date.now(),I=()=>({rolloutId:w,versionId:e.versionId,fields:b,rendered:O(a)});let o;try{o=await m({messages:a,turn:p})}catch(c){if(g){const u=p?.record();n.write(e.id,{...I(),...U(c),output:"",status:"failed",error:c instanceof Error?c.message:String(c),latencyMs:Date.now()-y,offeredTools:u?.offeredTools,steps:u?.steps})}throw c}const R=Date.now()-y;let k;if(g){const c=p?.record(),u=n.write(e.id,{...I(),model:o.model,output:o.output,status:o.status??"completed",error:o.error,inputTokens:o.inputTokens,outputTokens:o.outputTokens,cacheReadTokens:o.cacheReadTokens,cacheWriteTokens:o.cacheWriteTokens,citationTokens:o.citationTokens,reasoningTokens:o.reasoningTokens,latencyMs:R,caseId:o.caseId,seed:o.seed,offeredTools:o.offeredTools??c?.offeredTools,steps:o.steps??c?.steps});k=u instanceof Promise?u:void 0}return{...o,rolloutId:w,...k?{pricing:k}:{}}},bind:r=>v(T,r)};return T}export{D as MAX_RECORDED_MESSAGES,V as makePrompt,W as noRecorder};
@@ -0,0 +1,2 @@
1
+ /** The version this package was published as; a test holds it to `package.json`. */
2
+ export declare const PROMPT_VERSION = "0.9.1";
@@ -0,0 +1 @@
1
+ const o="0.9.1";export{o as PROMPT_VERSION};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spendgraph/prompt",
3
- "version": "0.8.2",
3
+ "version": "0.9.1",
4
4
  "description": "Pull a stored prompt or build one in code, render it, and record what it cost.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -42,12 +42,12 @@
42
42
  "README.md"
43
43
  ],
44
44
  "dependencies": {
45
- "@spendgraph/sdk": "^0.8.2"
45
+ "@spendgraph/sdk": "^0.9.1"
46
46
  },
47
47
  "devDependencies": {
48
- "@spendgraph/config": "0.8.2",
49
- "@spendgraph/llms": "^0.8.2",
50
- "@spendgraph/tools": "^0.8.2",
48
+ "@spendgraph/config": "0.9.1",
49
+ "@spendgraph/llms": "^0.9.1",
50
+ "@spendgraph/tools": "^0.9.1",
51
51
  "typescript": "^5"
52
52
  },
53
53
  "engines": {