@niscorp/signal 0.1.5 → 0.1.7

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/index.d.cts CHANGED
@@ -247,6 +247,7 @@ type CalibratedDecision<Q extends Question> = Q extends ChoiceQuestion<infer K>
247
247
  type DecideRequest<Qs extends Questions> = {
248
248
  state: DecideState;
249
249
  questions: Qs;
250
+ images?: Record<string, ImageSource>;
250
251
  options?: {
251
252
  signal?: AbortSignal;
252
253
  };
@@ -395,6 +396,7 @@ type DecisionRequest = {
395
396
  model: string;
396
397
  state: DecideState;
397
398
  questions: Questions;
399
+ images?: Record<string, ImageSource>;
398
400
  };
399
401
  type DecisionResponse = {
400
402
  model?: string;
package/dist/index.d.ts CHANGED
@@ -247,6 +247,7 @@ type CalibratedDecision<Q extends Question> = Q extends ChoiceQuestion<infer K>
247
247
  type DecideRequest<Qs extends Questions> = {
248
248
  state: DecideState;
249
249
  questions: Qs;
250
+ images?: Record<string, ImageSource>;
250
251
  options?: {
251
252
  signal?: AbortSignal;
252
253
  };
@@ -395,6 +396,7 @@ type DecisionRequest = {
395
396
  model: string;
396
397
  state: DecideState;
397
398
  questions: Questions;
399
+ images?: Record<string, ImageSource>;
398
400
  };
399
401
  type DecisionResponse = {
400
402
  model?: string;
package/dist/index.js CHANGED
@@ -482,17 +482,46 @@ var jsonOrText = (text) => {
482
482
  }
483
483
  };
484
484
  var providerError = (message, raw) => new SignalError(`Provider error: ${message}`, ErrorCode.PROVIDER_ERROR, { raw });
485
+ var FORMATS = { "image/png": "png", "image/jpeg": "jpeg" };
486
+ var assetOf = (id, source) => {
487
+ if (source.type === "url") {
488
+ throw new SignalError(`Image ${id}: TypeSafe takes image data, not a URL`, ErrorCode.VALIDATION_FAILED, { image: id });
489
+ }
490
+ const format = FORMATS[source.mediaType];
491
+ if (format === void 0) {
492
+ throw new SignalError(
493
+ `Image ${id}: TypeSafe takes image/png or image/jpeg, not ${source.mediaType}`,
494
+ ErrorCode.VALIDATION_FAILED,
495
+ { image: id }
496
+ );
497
+ }
498
+ return { type: "image", format, data_base64: source.data };
499
+ };
500
+ var assetsOf = (images) => {
501
+ const entries = Object.entries(images ?? {});
502
+ return entries.length === 0 ? void 0 : Object.fromEntries(entries.map(([id, source]) => [id, assetOf(id, source)]));
503
+ };
485
504
  var createSystemOneAdapter = async (config) => {
486
505
  const send = sendOf(config.client);
487
506
  const url = `${config.baseUrl.replace(/\/+$/, "")}/systemone`;
488
507
  const decide = async (request, options) => {
508
+ const assets = assetsOf(request.images);
489
509
  let status;
490
510
  let body;
491
511
  try {
492
512
  const response = await send(url, {
493
513
  method: "POST",
494
- headers: { authorization: `Bearer ${config.apiKey}`, "content-type": "application/json" },
495
- body: JSON.stringify({ model: request.model, state: request.state, questions: request.questions }),
514
+ headers: {
515
+ authorization: `Bearer ${config.apiKey}`,
516
+ "content-type": "application/json",
517
+ ...assets !== void 0 && { "TypeSafe-Danger-Zone-Images": "true" }
518
+ },
519
+ body: JSON.stringify({
520
+ model: request.model,
521
+ state: request.state,
522
+ questions: request.questions,
523
+ ...assets !== void 0 && { assets }
524
+ }),
496
525
  ...options?.signal !== void 0 && { signal: options.signal }
497
526
  });
498
527
  status = response.status;
@@ -548,6 +577,7 @@ var bareSchemaCorrection = (issues) => `Your output was invalid: ${issues}. Repl
548
577
  var decisionEmulationPrompt = (state) => `Answer every field of the OUTPUT SCHEMA about the STATE below. Each field's description is the question and lists everything you may answer with.
549
578
  STATE:
550
579
  ${state}`;
580
+ var decisionImageLabel = (id) => `Image ${id}:`;
551
581
  var decisionQuestionDescription = (question) => {
552
582
  if (question.type === "choice") return `${question.instructions} Options: ${JSON.stringify(question.criteria)}`;
553
583
  if (question.type === "score") {
@@ -1174,6 +1204,11 @@ function* ladder(text, strategies) {
1174
1204
  if (trimmed.length === 0) return;
1175
1205
  const direct = tryParse2(trimmed);
1176
1206
  if (direct.ok) yield { value: direct.value, rung: "parse" };
1207
+ const closed = closeTruncated(trimmed);
1208
+ if (closed !== void 0) {
1209
+ const parsed = tryParse2(closed);
1210
+ if (parsed.ok) yield { value: parsed.value, rung: "close-truncated" };
1211
+ }
1177
1212
  const extracted = extractJson(trimmed);
1178
1213
  if (extracted.ok) yield { value: extracted.value, rung: "extract" };
1179
1214
  for (const repaired of repairEscapeDamage(trimmed)) {
@@ -1186,11 +1221,6 @@ function* ladder(text, strategies) {
1186
1221
  if (parsed.ok) yield { value: parsed.value, rung: strategy.id };
1187
1222
  }
1188
1223
  }
1189
- const closed = closeTruncated(trimmed);
1190
- if (closed !== void 0) {
1191
- const parsed = tryParse2(closed);
1192
- if (parsed.ok) yield { value: parsed.value, rung: "close-truncated" };
1193
- }
1194
1224
  }
1195
1225
  var firstAccepted = (candidates, accept) => {
1196
1226
  let nearMiss;
@@ -1338,6 +1368,35 @@ var assertEffort = (config, effort) => {
1338
1368
  ErrorCode.VALIDATION_FAILED
1339
1369
  );
1340
1370
  };
1371
+ var imageId = z.uuid();
1372
+ var assertImageIds = (images) => {
1373
+ for (const id of Object.keys(images ?? {})) {
1374
+ if (!imageId.safeParse(id).success) {
1375
+ throw new SignalError(`Image key "${id}" is not a uuid`, ErrorCode.VALIDATION_FAILED, { image: id });
1376
+ }
1377
+ }
1378
+ };
1379
+ var assertTakesImages = (config) => {
1380
+ const resolved = modelRowOf(config);
1381
+ const row = resolved?.row;
1382
+ if (resolved === void 0 || row === void 0 || row.capabilities.multimodal) return;
1383
+ throw new SignalError(
1384
+ `${resolved.provider} ${resolved.model} takes no images (measured ${row.verified})`,
1385
+ ErrorCode.VALIDATION_FAILED
1386
+ );
1387
+ };
1388
+ var emulationContent = (state, images) => {
1389
+ const prompt = decisionEmulationPrompt(state);
1390
+ const entries = Object.entries(images ?? {});
1391
+ if (entries.length === 0) return prompt;
1392
+ return [
1393
+ { type: "text", text: prompt },
1394
+ ...entries.flatMap(([id, source]) => [
1395
+ { type: "text", text: decisionImageLabel(id) },
1396
+ { type: "image", source }
1397
+ ])
1398
+ ];
1399
+ };
1341
1400
  var wireIdsOf = (config) => {
1342
1401
  const source = typeof config.provider === "string" ? providerRegistry[config.provider] : config.provider;
1343
1402
  return source === void 0 || source.adapter === "systemone" ? [] : source.wire ?? [];
@@ -1515,7 +1574,12 @@ var createSignalFromConfig = (config) => {
1515
1574
  const stepStream = stepStreamAs("stepStream");
1516
1575
  const decideCalibrated = async (adapter, model, request, started) => {
1517
1576
  const response = await adapter.decide(
1518
- { model, state: request.state, questions: request.questions },
1577
+ {
1578
+ model,
1579
+ state: request.state,
1580
+ questions: request.questions,
1581
+ ...request.images !== void 0 && { images: request.images }
1582
+ },
1519
1583
  request.options?.signal !== void 0 ? { signal: request.options.signal } : void 0
1520
1584
  );
1521
1585
  const decisions = acceptCalibrated(request.questions, response.answers, response.raw);
@@ -1533,10 +1597,11 @@ var createSignalFromConfig = (config) => {
1533
1597
  };
1534
1598
  };
1535
1599
  const decideEmulated = async (model, request, started) => {
1600
+ if (Object.keys(request.images ?? {}).length > 0) assertTakesImages(config);
1536
1601
  const state = typeof request.state === "string" ? request.state : JSON.stringify(request.state);
1537
1602
  const result = await runComplete(
1538
1603
  {
1539
- messages: [{ role: "user", content: decisionEmulationPrompt(state) }],
1604
+ messages: [{ role: "user", content: emulationContent(state, request.images) }],
1540
1605
  schema: uncalibratedSchemaOf(request.questions),
1541
1606
  tools: void 0,
1542
1607
  retries: config.retries ?? 2,
@@ -1635,6 +1700,7 @@ var createSignalFromConfig = (config) => {
1635
1700
  }),
1636
1701
  decide: async (request) => {
1637
1702
  assertQuestions(request.questions);
1703
+ assertImageIds(request.images);
1638
1704
  const started = Date.now();
1639
1705
  const adapter = await getAdapter();
1640
1706
  const model = resolveProvider(config).model;