@claritylabs/cl-sdk 1.0.3 → 1.1.0

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/README.md CHANGED
@@ -27,13 +27,13 @@ npm install @claritylabs/cl-sdk pdf-lib zod
27
27
  import { createExtractor } from "@claritylabs/cl-sdk";
28
28
 
29
29
  const extractor = createExtractor({
30
- generateText: async ({ prompt, system, maxTokens, providerOptions }) => {
31
- const result = await yourProvider.generate({ prompt, system, maxTokens, providerOptions });
30
+ generateText: async ({ prompt, system, maxTokens, taskKind, budgetDiagnostics, providerOptions }) => {
31
+ const result = await yourProvider.generate({ prompt, system, maxTokens, taskKind, budgetDiagnostics, providerOptions });
32
32
  return { text: result.text, usage: result.usage };
33
33
  },
34
- generateObject: async ({ prompt, system, schema, maxTokens, providerOptions }) => {
34
+ generateObject: async ({ prompt, system, schema, maxTokens, taskKind, budgetDiagnostics, providerOptions }) => {
35
35
  // Pass providerOptions.pdfBase64 and/or providerOptions.images to your model
36
- const result = await yourProvider.generateStructured({ prompt, system, schema, maxTokens, providerOptions });
36
+ const result = await yourProvider.generateStructured({ prompt, system, schema, maxTokens, taskKind, budgetDiagnostics, providerOptions });
37
37
  return { object: result.object, usage: result.usage };
38
38
  },
39
39
  concurrency: 3,
@@ -120,6 +120,10 @@ Important: your `generateObject` callback must actually forward multimodal paylo
120
120
 
121
121
  If your callback ignores those fields, the model will only see the text prompt.
122
122
 
123
+ ## Model routing metadata
124
+
125
+ Every SDK model callback may receive `taskKind` and `budgetDiagnostics`. Hosts can use these provider-agnostic fields for cheap-first routing, fallback, and telemetry without the SDK hardcoding model names. Example task kinds include `extraction_classify`, `extraction_focused`, `extraction_review`, `query_reason`, `application_extract_fields`, and `pce_impact_analysis`. `budgetDiagnostics` includes the resolved max-token budget and truncation-risk warnings for the current subtask.
126
+
123
127
  ## Bounded Agentic Workflows
124
128
 
125
129
  CL-SDK uses deterministic scaffolding with agentic decision points rather than fixed all-tools-all-the-time chains:
package/dist/index.d.mts CHANGED
@@ -68,6 +68,10 @@ type GenerateText = (params: {
68
68
  prompt: string;
69
69
  system?: string;
70
70
  maxTokens: number;
71
+ /** Provider-agnostic subtask label for host-side model routing, fallback, and telemetry. */
72
+ taskKind?: ModelTaskKind;
73
+ /** Resolved budget diagnostics for hosts that route/escalate based on truncation risk. */
74
+ budgetDiagnostics?: ModelBudgetResolution;
71
75
  providerOptions?: Record<string, unknown>;
72
76
  }) => Promise<{
73
77
  text: string;
@@ -96,6 +100,10 @@ type GenerateObject<T = unknown> = (params: {
96
100
  system?: string;
97
101
  schema: ZodSchema<T>;
98
102
  maxTokens: number;
103
+ /** Provider-agnostic subtask label for host-side model routing, fallback, and telemetry. */
104
+ taskKind?: ModelTaskKind;
105
+ /** Resolved budget diagnostics for hosts that route/escalate based on truncation risk. */
106
+ budgetDiagnostics?: ModelBudgetResolution;
99
107
  providerOptions?: Record<string, unknown>;
100
108
  }) => Promise<{
101
109
  object: T;
@@ -160,6 +168,8 @@ interface SafeGenerateParams {
160
168
  prompt: string;
161
169
  system?: string;
162
170
  maxTokens: number;
171
+ taskKind?: ModelTaskKind;
172
+ budgetDiagnostics?: ModelBudgetResolution;
163
173
  providerOptions?: Record<string, unknown>;
164
174
  }
165
175
  /**
package/dist/index.d.ts CHANGED
@@ -68,6 +68,10 @@ type GenerateText = (params: {
68
68
  prompt: string;
69
69
  system?: string;
70
70
  maxTokens: number;
71
+ /** Provider-agnostic subtask label for host-side model routing, fallback, and telemetry. */
72
+ taskKind?: ModelTaskKind;
73
+ /** Resolved budget diagnostics for hosts that route/escalate based on truncation risk. */
74
+ budgetDiagnostics?: ModelBudgetResolution;
71
75
  providerOptions?: Record<string, unknown>;
72
76
  }) => Promise<{
73
77
  text: string;
@@ -96,6 +100,10 @@ type GenerateObject<T = unknown> = (params: {
96
100
  system?: string;
97
101
  schema: ZodSchema<T>;
98
102
  maxTokens: number;
103
+ /** Provider-agnostic subtask label for host-side model routing, fallback, and telemetry. */
104
+ taskKind?: ModelTaskKind;
105
+ /** Resolved budget diagnostics for hosts that route/escalate based on truncation risk. */
106
+ budgetDiagnostics?: ModelBudgetResolution;
99
107
  providerOptions?: Record<string, unknown>;
100
108
  }) => Promise<{
101
109
  object: T;
@@ -160,6 +168,8 @@ interface SafeGenerateParams {
160
168
  prompt: string;
161
169
  system?: string;
162
170
  maxTokens: number;
171
+ taskKind?: ModelTaskKind;
172
+ budgetDiagnostics?: ModelBudgetResolution;
163
173
  providerOptions?: Record<string, unknown>;
164
174
  }
165
175
  /**
package/dist/index.js CHANGED
@@ -2835,6 +2835,8 @@ async function runExtractor(params) {
2835
2835
  generateObject,
2836
2836
  convertPdfToImages,
2837
2837
  maxTokens = 4096,
2838
+ taskKind,
2839
+ budgetDiagnostics,
2838
2840
  providerOptions,
2839
2841
  pageRangeCache
2840
2842
  } = params;
@@ -2868,6 +2870,8 @@ async function runExtractor(params) {
2868
2870
  prompt: fullPrompt,
2869
2871
  schema: strictSchema,
2870
2872
  maxTokens,
2873
+ taskKind,
2874
+ budgetDiagnostics,
2871
2875
  providerOptions: extractorProviderOptions
2872
2876
  })
2873
2877
  );
@@ -3847,6 +3851,8 @@ async function formatDocumentContent(doc, generateText, options) {
3847
3851
  () => generateText({
3848
3852
  prompt,
3849
3853
  maxTokens: options?.maxTokens ?? 16384,
3854
+ taskKind: options?.taskKind,
3855
+ budgetDiagnostics: options?.budgetDiagnostics,
3850
3856
  providerOptions: options?.providerOptions
3851
3857
  })
3852
3858
  );
@@ -7110,6 +7116,8 @@ If you cannot find the section, return startPage: 0 and endPage: 0.
7110
7116
  Return JSON only.`,
7111
7117
  schema: PageLocationSchema,
7112
7118
  maxTokens: budget.maxTokens,
7119
+ taskKind: "extraction_referential_lookup",
7120
+ budgetDiagnostics: budget,
7113
7121
  providerOptions: await buildPdfProviderOptions(pdfInput, providerOptions)
7114
7122
  },
7115
7123
  {
@@ -7256,6 +7264,8 @@ async function resolveReferentialCoverages(params) {
7256
7264
  getPageRangePdf,
7257
7265
  getPageImages,
7258
7266
  maxTokens: budget.maxTokens,
7267
+ taskKind: "extraction_referential_lookup",
7268
+ budgetDiagnostics: budget,
7259
7269
  providerOptions
7260
7270
  });
7261
7271
  trackUsage(result.usage);
@@ -7372,6 +7382,8 @@ async function runFocusedExtractorWithFallback(params) {
7372
7382
  generateObject,
7373
7383
  convertPdfToImages,
7374
7384
  maxTokens: budget.maxTokens,
7385
+ taskKind,
7386
+ budgetDiagnostics: budget,
7375
7387
  providerOptions,
7376
7388
  pageRangeCache,
7377
7389
  getPageRangePdf,
@@ -7415,6 +7427,8 @@ async function runFocusedExtractorWithFallback(params) {
7415
7427
  generateObject,
7416
7428
  convertPdfToImages,
7417
7429
  maxTokens: budget.maxTokens,
7430
+ taskKind,
7431
+ budgetDiagnostics: budget,
7418
7432
  providerOptions,
7419
7433
  pageRangeCache,
7420
7434
  getPageRangePdf,
@@ -8277,6 +8291,8 @@ function createExtractor(config) {
8277
8291
  generateObject,
8278
8292
  convertPdfToImages,
8279
8293
  maxTokens: budget.maxTokens,
8294
+ taskKind: "extraction_focused",
8295
+ budgetDiagnostics: budget,
8280
8296
  providerOptions: activeProviderOptions,
8281
8297
  pageRangeCache,
8282
8298
  getPageRangePdf,
@@ -8425,6 +8441,8 @@ function createExtractor(config) {
8425
8441
  prompt: buildClassifyPrompt(),
8426
8442
  schema: ClassifyResultSchema,
8427
8443
  maxTokens: budget.maxTokens,
8444
+ taskKind: "extraction_classify",
8445
+ budgetDiagnostics: budget,
8428
8446
  providerOptions: await getFullPdfProviderOptions()
8429
8447
  },
8430
8448
  {
@@ -8473,6 +8491,8 @@ function createExtractor(config) {
8473
8491
  prompt: buildFormInventoryPrompt(templateHints),
8474
8492
  schema: FormInventorySchema,
8475
8493
  maxTokens: budget.maxTokens,
8494
+ taskKind: "extraction_form_inventory",
8495
+ budgetDiagnostics: budget,
8476
8496
  providerOptions: await getFullPdfProviderOptions()
8477
8497
  },
8478
8498
  {
@@ -8525,6 +8545,8 @@ function createExtractor(config) {
8525
8545
  prompt: buildPageMapPrompt(templateHints, startPage, endPage, formInventoryHint),
8526
8546
  schema: PageMapChunkSchema,
8527
8547
  maxTokens: budget.maxTokens,
8548
+ taskKind: "extraction_page_map",
8549
+ budgetDiagnostics: budget,
8528
8550
  providerOptions: { ...activeProviderOptions, pdfBase64: pagesPdf }
8529
8551
  },
8530
8552
  {
@@ -8641,6 +8663,8 @@ function createExtractor(config) {
8641
8663
  generateObject,
8642
8664
  convertPdfToImages,
8643
8665
  maxTokens: budget.maxTokens,
8666
+ taskKind: "extraction_focused",
8667
+ budgetDiagnostics: budget,
8644
8668
  providerOptions: activeProviderOptions,
8645
8669
  pageRangeCache: completedPageRangePdfCache,
8646
8670
  getPageRangePdf,
@@ -8731,10 +8755,19 @@ function createExtractor(config) {
8731
8755
  prompt: buildReviewPrompt(template.required, extractedKeys, extractionSummary, pageMapSummary, extractorCatalog),
8732
8756
  schema: ReviewResultSchema,
8733
8757
  maxTokens: budget.maxTokens,
8758
+ taskKind: "extraction_review",
8759
+ budgetDiagnostics: budget,
8734
8760
  providerOptions: await getFullPdfProviderOptions()
8735
8761
  },
8736
8762
  {
8737
- fallback: { complete: true, missingFields: [], qualityIssues: [], additionalTasks: [] },
8763
+ fallback: {
8764
+ complete: false,
8765
+ missingFields: ["llm_review_unavailable"],
8766
+ qualityIssues: [
8767
+ "LLM extraction review failed; deterministic review was used and the result needs review."
8768
+ ],
8769
+ additionalTasks: []
8770
+ },
8738
8771
  log,
8739
8772
  onError: (err, attempt) => log?.(`Review round ${round + 1} attempt ${attempt + 1} failed: ${err}`)
8740
8773
  }
@@ -8835,6 +8868,8 @@ function createExtractor(config) {
8835
8868
  prompt: buildSummaryPrompt(document),
8836
8869
  schema: SummaryResultSchema,
8837
8870
  maxTokens: budget.maxTokens,
8871
+ taskKind: "extraction_summary",
8872
+ budgetDiagnostics: budget,
8838
8873
  providerOptions: activeProviderOptions
8839
8874
  },
8840
8875
  {
@@ -8862,6 +8897,8 @@ function createExtractor(config) {
8862
8897
  const formatResult = await formatDocumentContent(document, generateText, {
8863
8898
  providerOptions: activeProviderOptions,
8864
8899
  maxTokens: formatBudget.maxTokens,
8900
+ taskKind: "extraction_format",
8901
+ budgetDiagnostics: formatBudget,
8865
8902
  concurrency: formatConcurrency ?? concurrency,
8866
8903
  onProgress,
8867
8904
  log
@@ -9264,6 +9301,7 @@ async function classifyApplication(pdfContent, generateObject, providerOptions,
9264
9301
  Analyze the attached insurance document. If text source units are provided in provider options, use them as supporting context. Do not infer from base64 text.`,
9265
9302
  schema: ApplicationClassifyResultSchema,
9266
9303
  maxTokens,
9304
+ taskKind: "application_classify",
9267
9305
  providerOptions: {
9268
9306
  ...providerOptions,
9269
9307
  pdfBase64: providerOptions?.pdfBase64 ?? pdfContent
@@ -9366,6 +9404,7 @@ Extract fields from the attached application PDF. Use provider-supplied source u
9366
9404
  prompt,
9367
9405
  schema: FieldExtractionResultSchema,
9368
9406
  maxTokens,
9407
+ taskKind: "application_extract_fields",
9369
9408
  providerOptions: {
9370
9409
  ...providerOptions,
9371
9410
  pdfBase64: providerOptions?.pdfBase64 ?? pdfContent
@@ -9419,6 +9458,7 @@ async function autoFillFromContext(fields, orgContext, generateObject, providerO
9419
9458
  prompt,
9420
9459
  schema: AutoFillResultSchema,
9421
9460
  maxTokens,
9461
+ taskKind: "application_auto_fill",
9422
9462
  providerOptions
9423
9463
  })
9424
9464
  );
@@ -9489,6 +9529,7 @@ async function batchQuestions(unfilledFields, generateObject, providerOptions, m
9489
9529
  prompt,
9490
9530
  schema: QuestionBatchResultSchema,
9491
9531
  maxTokens,
9532
+ taskKind: "application_batch",
9492
9533
  providerOptions
9493
9534
  })
9494
9535
  );
@@ -9540,6 +9581,7 @@ async function classifyReplyIntent(fields, replyText, generateObject, providerOp
9540
9581
  prompt,
9541
9582
  schema: ReplyIntentSchema,
9542
9583
  maxTokens,
9584
+ taskKind: "application_classify",
9543
9585
  providerOptions
9544
9586
  })
9545
9587
  );
@@ -9599,6 +9641,7 @@ async function parseAnswers(fields, replyText, generateObject, providerOptions,
9599
9641
  prompt,
9600
9642
  schema: AnswerParsingResultSchema,
9601
9643
  maxTokens,
9644
+ taskKind: "application_parse_answers",
9602
9645
  providerOptions
9603
9646
  })
9604
9647
  );
@@ -9728,6 +9771,7 @@ async function fillFromLookup(requests, targetFields, availableData, generateObj
9728
9771
  prompt,
9729
9772
  schema: LookupFillResultSchema,
9730
9773
  maxTokens,
9774
+ taskKind: "application_lookup",
9731
9775
  providerOptions
9732
9776
  })
9733
9777
  );
@@ -9810,6 +9854,7 @@ async function generateBatchEmail(batchFields, batchIndex, totalBatches, opts, g
9810
9854
  () => generateText({
9811
9855
  prompt,
9812
9856
  maxTokens,
9857
+ taskKind: "application_email",
9813
9858
  providerOptions
9814
9859
  })
9815
9860
  );
@@ -10332,11 +10377,14 @@ function createApplicationPipeline(config) {
10332
10377
  }
10333
10378
  if (replyPlan.answerQuestion && intent.questionText) {
10334
10379
  try {
10380
+ const budget = resolveBudget("application_email", 512);
10335
10381
  const { text, usage } = await generateText({
10336
10382
  prompt: `The user is filling out an insurance application and asked: "${intent.questionText}"
10337
10383
 
10338
10384
  Provide a brief, helpful explanation (2-3 sentences). End with "Just reply with the answer when you're ready and I'll fill it in."`,
10339
- maxTokens: resolveBudget("application_email", 512).maxTokens,
10385
+ maxTokens: budget.maxTokens,
10386
+ taskKind: "application_email",
10387
+ budgetDiagnostics: budget,
10340
10388
  providerOptions
10341
10389
  });
10342
10390
  trackUsage(usage);
@@ -10461,6 +10509,7 @@ ${emailText}`;
10461
10509
  if (!state) throw new Error(`Application ${applicationId} not found`);
10462
10510
  const filledFields = state.fields.filter((f) => f.value);
10463
10511
  const fieldSummary = filledFields.map((f) => `${f.section} > ${f.label}: ${f.value} (source: ${f.source ?? "unknown"})`).join("\n");
10512
+ const budget = resolveBudget("application_email", 4096);
10464
10513
  const { text, usage } = await generateText({
10465
10514
  prompt: `Format these filled insurance application fields as a clean confirmation summary for the user to review. Group by section, show each field as "Label: Value". End with a note asking them to confirm or request changes.
10466
10515
 
@@ -10468,7 +10517,9 @@ Application: ${state.title ?? "Insurance Application"}
10468
10517
 
10469
10518
  Fields:
10470
10519
  ${fieldSummary}`,
10471
- maxTokens: resolveBudget("application_email", 4096).maxTokens,
10520
+ maxTokens: budget.maxTokens,
10521
+ taskKind: "application_email",
10522
+ budgetDiagnostics: budget,
10472
10523
  providerOptions
10473
10524
  });
10474
10525
  trackUsage(usage);
@@ -10942,6 +10993,8 @@ ${e.text}`;
10942
10993
  prompt,
10943
10994
  schema: SubAnswerSchema,
10944
10995
  maxTokens: budget.maxTokens,
10996
+ taskKind: "query_reason",
10997
+ budgetDiagnostics: budget,
10945
10998
  providerOptions
10946
10999
  })
10947
11000
  );
@@ -11165,6 +11218,8 @@ async function verify(originalQuestion, subAnswers, allEvidence, config) {
11165
11218
  prompt,
11166
11219
  schema: VerifyResultSchema,
11167
11220
  maxTokens: budget.maxTokens,
11221
+ taskKind: "query_verify",
11222
+ budgetDiagnostics: budget,
11168
11223
  providerOptions
11169
11224
  })
11170
11225
  );
@@ -11307,6 +11362,8 @@ async function interpretAttachments(params) {
11307
11362
  prompt,
11308
11363
  schema: AttachmentInterpretationSchema,
11309
11364
  maxTokens: budget.maxTokens,
11365
+ taskKind: "query_attachment",
11366
+ budgetDiagnostics: budget,
11310
11367
  providerOptions: buildAttachmentProviderOptions(attachment, providerOptions)
11311
11368
  },
11312
11369
  {
@@ -11644,6 +11701,8 @@ function createQueryAgent(config) {
11644
11701
  prompt,
11645
11702
  schema: QueryClassifyResultSchema,
11646
11703
  maxTokens: budget.maxTokens,
11704
+ taskKind: "query_classify",
11705
+ budgetDiagnostics: budget,
11647
11706
  providerOptions
11648
11707
  },
11649
11708
  {
@@ -11695,6 +11754,8 @@ function createQueryAgent(config) {
11695
11754
  prompt,
11696
11755
  schema: QueryResultSchema,
11697
11756
  maxTokens: budget.maxTokens,
11757
+ taskKind: "query_respond",
11758
+ budgetDiagnostics: budget,
11698
11759
  providerOptions
11699
11760
  },
11700
11761
  {
@@ -11790,6 +11851,8 @@ function createPceAgent(config = {}) {
11790
11851
  prompt: buildPceNormalizePrompt({ requestText: input.requestText, evidenceSources }),
11791
11852
  schema: PceNormalizationResultSchema,
11792
11853
  maxTokens: budget.maxTokens,
11854
+ taskKind: "pce_impact_analysis",
11855
+ budgetDiagnostics: budget,
11793
11856
  providerOptions: config.providerOptions
11794
11857
  },
11795
11858
  { fallback, maxRetries: 1, log: config.log }
@@ -11851,6 +11914,8 @@ function createPceAgent(config = {}) {
11851
11914
  }),
11852
11915
  schema: ReplyAnswersSchema,
11853
11916
  maxTokens: budget.maxTokens,
11917
+ taskKind: "pce_reply_parse",
11918
+ budgetDiagnostics: budget,
11854
11919
  providerOptions: config.providerOptions
11855
11920
  },
11856
11921
  { fallback: { answers }, maxRetries: 1, log: config.log }