@xbbg/langgraph 1.3.0 → 1.4.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/README.md +29 -0
- package/dist/index.d.ts +66 -3
- package/dist/index.js +512 -17
- package/dist/index.js.map +1 -1
- package/package.json +6 -3
package/dist/index.js
CHANGED
|
@@ -51,6 +51,7 @@ var BLOOMBERG_TOOL_NAMES = [
|
|
|
51
51
|
"xbbg_ext_cdx",
|
|
52
52
|
"xbbg_ext_currency",
|
|
53
53
|
"xbbg_ext_bql_builder",
|
|
54
|
+
"xbbg_ext_chart_spec",
|
|
54
55
|
"xbbg_ext_market_session",
|
|
55
56
|
"xbbg_ext_yas_overrides",
|
|
56
57
|
"xbbg_ext_constants",
|
|
@@ -244,12 +245,12 @@ function rowCountOf(value) {
|
|
|
244
245
|
if (typeof value !== "object" || value === null) {
|
|
245
246
|
return null;
|
|
246
247
|
}
|
|
247
|
-
const
|
|
248
|
-
const rowCount =
|
|
248
|
+
const record3 = value;
|
|
249
|
+
const rowCount = record3.rowCount;
|
|
249
250
|
if (typeof rowCount === "number" && Number.isInteger(rowCount) && rowCount >= 0) {
|
|
250
251
|
return rowCount;
|
|
251
252
|
}
|
|
252
|
-
const updateCount =
|
|
253
|
+
const updateCount = record3.updateCount;
|
|
253
254
|
if (typeof updateCount === "number" && Number.isInteger(updateCount) && updateCount >= 0) {
|
|
254
255
|
return updateCount;
|
|
255
256
|
}
|
|
@@ -401,6 +402,389 @@ function createBloombergStructuredTool(func, fields) {
|
|
|
401
402
|
);
|
|
402
403
|
}
|
|
403
404
|
|
|
405
|
+
// src/chart-spec.ts
|
|
406
|
+
var VEGA_SCHEMA = "https://vega.github.io/schema/vega-lite/v5.json";
|
|
407
|
+
var COMPONENT_NAME = "xbbg_chart";
|
|
408
|
+
var X_FIELD_CANDIDATES = ["date", "time", "datetime", "timestamp"];
|
|
409
|
+
var LABEL_FIELD_CANDIDATES = ["ticker", "security", "member", "name", "label"];
|
|
410
|
+
var SERIES_FIELD_CANDIDATES = ["ticker", "security", "field", "side", "category"];
|
|
411
|
+
var VALUE_FIELD_CANDIDATES = [
|
|
412
|
+
"value",
|
|
413
|
+
"PX_LAST",
|
|
414
|
+
"close",
|
|
415
|
+
"price",
|
|
416
|
+
"weight",
|
|
417
|
+
"marketValue",
|
|
418
|
+
"market_value"
|
|
419
|
+
];
|
|
420
|
+
var OPEN_FIELD_CANDIDATES = ["open", "OPEN", "PX_OPEN"];
|
|
421
|
+
var HIGH_FIELD_CANDIDATES = ["high", "HIGH", "PX_HIGH"];
|
|
422
|
+
var LOW_FIELD_CANDIDATES = ["low", "LOW", "PX_LOW"];
|
|
423
|
+
var CLOSE_FIELD_CANDIDATES = ["close", "CLOSE", "PX_LAST", "last", "value"];
|
|
424
|
+
var SIDE_FIELD_CANDIDATES = ["side", "SIDE", "type"];
|
|
425
|
+
var PRICE_FIELD_CANDIDATES = ["price", "PRICE", "px", "PX"];
|
|
426
|
+
var SIZE_FIELD_CANDIDATES = ["size", "SIZE", "quantity", "qty", "volume"];
|
|
427
|
+
function defaultChartForSource(source) {
|
|
428
|
+
switch (source) {
|
|
429
|
+
case "bdib":
|
|
430
|
+
return "candlestick";
|
|
431
|
+
case "depth":
|
|
432
|
+
return "depth";
|
|
433
|
+
case "holdings":
|
|
434
|
+
return "bar";
|
|
435
|
+
case "bdh":
|
|
436
|
+
case "rows":
|
|
437
|
+
return "line";
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
function fieldExists(rows, field) {
|
|
441
|
+
for (const row of rows) {
|
|
442
|
+
if (Object.prototype.hasOwnProperty.call(row, field)) {
|
|
443
|
+
return true;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
return false;
|
|
447
|
+
}
|
|
448
|
+
function findCandidateField(rows, candidates) {
|
|
449
|
+
for (const candidate of candidates) {
|
|
450
|
+
if (fieldExists(rows, candidate)) {
|
|
451
|
+
return candidate;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
const first = rows[0];
|
|
455
|
+
if (first === void 0) {
|
|
456
|
+
return void 0;
|
|
457
|
+
}
|
|
458
|
+
const keys = Object.keys(first);
|
|
459
|
+
for (const candidate of candidates) {
|
|
460
|
+
const lower = candidate.toLowerCase();
|
|
461
|
+
const match = keys.find((key) => key.toLowerCase() === lower);
|
|
462
|
+
if (match !== void 0 && fieldExists(rows, match)) {
|
|
463
|
+
return match;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
return void 0;
|
|
467
|
+
}
|
|
468
|
+
function requireField(rows, field, label, candidates) {
|
|
469
|
+
const resolved = field ?? findCandidateField(rows, candidates);
|
|
470
|
+
if (resolved === void 0 || !fieldExists(rows, resolved)) {
|
|
471
|
+
throw new Error(
|
|
472
|
+
`Missing ${label}; pass ${label} explicitly or include one of: ${candidates.join(", ")}`
|
|
473
|
+
);
|
|
474
|
+
}
|
|
475
|
+
return resolved;
|
|
476
|
+
}
|
|
477
|
+
function hasFiniteNumber(rows, field) {
|
|
478
|
+
for (const row of rows) {
|
|
479
|
+
if (typeof row[field] === "number" && Number.isFinite(row[field])) {
|
|
480
|
+
return true;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
return false;
|
|
484
|
+
}
|
|
485
|
+
function firstNumericField(rows, excludedField) {
|
|
486
|
+
const first = rows[0];
|
|
487
|
+
if (first === void 0) {
|
|
488
|
+
return void 0;
|
|
489
|
+
}
|
|
490
|
+
for (const key of Object.keys(first)) {
|
|
491
|
+
if (key !== excludedField && hasFiniteNumber(rows, key)) {
|
|
492
|
+
return key;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
return void 0;
|
|
496
|
+
}
|
|
497
|
+
function requireNumericField(rows, field, label) {
|
|
498
|
+
if (!hasFiniteNumber(rows, field)) {
|
|
499
|
+
throw new Error(`${label} (${field}) must contain at least one finite numeric value`);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
function inferVegaType(rows, field) {
|
|
503
|
+
for (const row of rows) {
|
|
504
|
+
const value = row[field];
|
|
505
|
+
if (typeof value === "number") {
|
|
506
|
+
return "quantitative";
|
|
507
|
+
}
|
|
508
|
+
if (typeof value === "string" && (/^\d{4}-\d{2}-\d{2}(?:$|[T\s])/u.test(value) || /^\d{8}$/u.test(value))) {
|
|
509
|
+
return "temporal";
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
return "nominal";
|
|
513
|
+
}
|
|
514
|
+
function normalizeTemporalRows(rows, field) {
|
|
515
|
+
let normalized;
|
|
516
|
+
for (let index = 0; index < rows.length; index += 1) {
|
|
517
|
+
const row = rows[index];
|
|
518
|
+
if (row === void 0) {
|
|
519
|
+
continue;
|
|
520
|
+
}
|
|
521
|
+
const value = row[field];
|
|
522
|
+
if (typeof value !== "string" || !/^\d{8}$/u.test(value)) {
|
|
523
|
+
normalized?.push(row);
|
|
524
|
+
continue;
|
|
525
|
+
}
|
|
526
|
+
normalized ??= rows.slice(0, index);
|
|
527
|
+
normalized.push({
|
|
528
|
+
...row,
|
|
529
|
+
[field]: `${value.slice(0, 4)}-${value.slice(4, 6)}-${value.slice(6, 8)}`
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
return normalized ?? rows;
|
|
533
|
+
}
|
|
534
|
+
function tooltip(fields) {
|
|
535
|
+
return fields.map((field) => ({
|
|
536
|
+
field,
|
|
537
|
+
type: field === "_xbbg_value" ? "quantitative" : "nominal"
|
|
538
|
+
}));
|
|
539
|
+
}
|
|
540
|
+
function datumField(field) {
|
|
541
|
+
return `datum[${JSON.stringify(field)}]`;
|
|
542
|
+
}
|
|
543
|
+
function buildGenericSpec(input, rows, chart, title) {
|
|
544
|
+
const xField = requireField(rows, input.xField, "xField", X_FIELD_CANDIDATES);
|
|
545
|
+
let yFields;
|
|
546
|
+
if (input.yFields !== void 0) {
|
|
547
|
+
yFields = input.yFields;
|
|
548
|
+
} else {
|
|
549
|
+
const yField = findCandidateField(rows, VALUE_FIELD_CANDIDATES) ?? firstNumericField(rows, xField);
|
|
550
|
+
if (yField === void 0) {
|
|
551
|
+
throw new Error("Missing yFields; include at least one numeric value field");
|
|
552
|
+
}
|
|
553
|
+
yFields = [yField];
|
|
554
|
+
}
|
|
555
|
+
if (yFields.length === 0) {
|
|
556
|
+
throw new Error("Missing yFields; include at least one numeric value field");
|
|
557
|
+
}
|
|
558
|
+
for (const field of yFields) {
|
|
559
|
+
if (!fieldExists(rows, field)) {
|
|
560
|
+
throw new Error(`Missing y field: ${field}`);
|
|
561
|
+
}
|
|
562
|
+
requireNumericField(rows, field, "yField");
|
|
563
|
+
}
|
|
564
|
+
const normalizedRows = inferVegaType(rows, xField) === "temporal" ? normalizeTemporalRows(rows, xField) : rows;
|
|
565
|
+
const seriesField = input.seriesField ?? (yFields.length === 1 ? findCandidateField(rows, SERIES_FIELD_CANDIDATES) : void 0);
|
|
566
|
+
if (seriesField !== void 0 && !fieldExists(rows, seriesField)) {
|
|
567
|
+
throw new Error(`Missing series field: ${seriesField}`);
|
|
568
|
+
}
|
|
569
|
+
const mark = chart === "scatter" ? "point" : chart;
|
|
570
|
+
const encoding = {
|
|
571
|
+
x: { field: xField, title: xField, type: inferVegaType(normalizedRows, xField) }
|
|
572
|
+
};
|
|
573
|
+
const transform = [];
|
|
574
|
+
if (yFields.length === 1) {
|
|
575
|
+
const yField = yFields[0];
|
|
576
|
+
if (yField === void 0) {
|
|
577
|
+
throw new Error("Missing yFields; include at least one numeric value field");
|
|
578
|
+
}
|
|
579
|
+
encoding.y = { field: yField, title: yField, type: "quantitative" };
|
|
580
|
+
if (seriesField !== void 0) {
|
|
581
|
+
encoding.color = { field: seriesField, title: seriesField, type: "nominal" };
|
|
582
|
+
}
|
|
583
|
+
encoding.tooltip = tooltip([
|
|
584
|
+
xField,
|
|
585
|
+
...seriesField === void 0 ? [] : [seriesField],
|
|
586
|
+
yField
|
|
587
|
+
]);
|
|
588
|
+
} else {
|
|
589
|
+
transform.push({ as: ["_xbbg_series", "_xbbg_value"], fold: yFields });
|
|
590
|
+
encoding.y = { field: "_xbbg_value", title: "value", type: "quantitative" };
|
|
591
|
+
encoding.color = { field: "_xbbg_series", title: "series", type: "nominal" };
|
|
592
|
+
if (seriesField !== void 0) {
|
|
593
|
+
encoding.detail = { field: seriesField, type: "nominal" };
|
|
594
|
+
}
|
|
595
|
+
encoding.tooltip = tooltip([
|
|
596
|
+
xField,
|
|
597
|
+
...seriesField === void 0 ? [] : [seriesField],
|
|
598
|
+
"_xbbg_series",
|
|
599
|
+
"_xbbg_value"
|
|
600
|
+
]);
|
|
601
|
+
}
|
|
602
|
+
const spec = {
|
|
603
|
+
$schema: VEGA_SCHEMA,
|
|
604
|
+
data: { values: normalizedRows },
|
|
605
|
+
description: `xbbg ${chart} chart spec for ${input.source}`,
|
|
606
|
+
mark: { type: mark, tooltip: true },
|
|
607
|
+
title,
|
|
608
|
+
...transform.length === 0 ? {} : { transform },
|
|
609
|
+
encoding
|
|
610
|
+
};
|
|
611
|
+
return { spec, xField, yFields, ...seriesField === void 0 ? {} : { seriesField } };
|
|
612
|
+
}
|
|
613
|
+
function buildBarSpec(input, rows, title) {
|
|
614
|
+
const xField = requireField(
|
|
615
|
+
rows,
|
|
616
|
+
input.xField ?? input.labelField,
|
|
617
|
+
"labelField",
|
|
618
|
+
LABEL_FIELD_CANDIDATES
|
|
619
|
+
);
|
|
620
|
+
const yField = requireField(
|
|
621
|
+
rows,
|
|
622
|
+
input.valueField ?? input.yFields?.[0],
|
|
623
|
+
"valueField",
|
|
624
|
+
VALUE_FIELD_CANDIDATES
|
|
625
|
+
);
|
|
626
|
+
requireNumericField(rows, yField, "valueField");
|
|
627
|
+
const seriesField = input.seriesField;
|
|
628
|
+
if (seriesField !== void 0 && !fieldExists(rows, seriesField)) {
|
|
629
|
+
throw new Error(`Missing series field: ${seriesField}`);
|
|
630
|
+
}
|
|
631
|
+
const encoding = {
|
|
632
|
+
x: { field: xField, sort: "-y", title: xField, type: inferVegaType(rows, xField) },
|
|
633
|
+
y: { field: yField, title: yField, type: "quantitative" },
|
|
634
|
+
tooltip: tooltip([xField, ...seriesField === void 0 ? [] : [seriesField], yField])
|
|
635
|
+
};
|
|
636
|
+
if (seriesField !== void 0) {
|
|
637
|
+
encoding.color = { field: seriesField, title: seriesField, type: "nominal" };
|
|
638
|
+
}
|
|
639
|
+
return {
|
|
640
|
+
spec: {
|
|
641
|
+
$schema: VEGA_SCHEMA,
|
|
642
|
+
data: { values: rows },
|
|
643
|
+
description: `xbbg bar chart spec for ${input.source}`,
|
|
644
|
+
encoding,
|
|
645
|
+
mark: { type: "bar", tooltip: true },
|
|
646
|
+
title
|
|
647
|
+
},
|
|
648
|
+
xField,
|
|
649
|
+
yFields: [yField],
|
|
650
|
+
...seriesField === void 0 ? {} : { seriesField }
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
function buildCandlestickSpec(input, rows, title) {
|
|
654
|
+
const xField = requireField(rows, input.xField, "xField", X_FIELD_CANDIDATES);
|
|
655
|
+
const openField = requireField(rows, input.openField, "openField", OPEN_FIELD_CANDIDATES);
|
|
656
|
+
const highField = requireField(rows, input.highField, "highField", HIGH_FIELD_CANDIDATES);
|
|
657
|
+
const lowField = requireField(rows, input.lowField, "lowField", LOW_FIELD_CANDIDATES);
|
|
658
|
+
const closeField = requireField(rows, input.closeField, "closeField", CLOSE_FIELD_CANDIDATES);
|
|
659
|
+
for (const [label, field] of [
|
|
660
|
+
["openField", openField],
|
|
661
|
+
["highField", highField],
|
|
662
|
+
["lowField", lowField],
|
|
663
|
+
["closeField", closeField]
|
|
664
|
+
]) {
|
|
665
|
+
requireNumericField(rows, field, label);
|
|
666
|
+
}
|
|
667
|
+
const normalizedRows = inferVegaType(rows, xField) === "temporal" ? normalizeTemporalRows(rows, xField) : rows;
|
|
668
|
+
const color = {
|
|
669
|
+
condition: { test: `${datumField(closeField)} >= ${datumField(openField)}`, value: "#137333" },
|
|
670
|
+
value: "#c5221f"
|
|
671
|
+
};
|
|
672
|
+
return {
|
|
673
|
+
spec: {
|
|
674
|
+
$schema: VEGA_SCHEMA,
|
|
675
|
+
data: { values: normalizedRows },
|
|
676
|
+
description: `xbbg candlestick chart spec for ${input.source}`,
|
|
677
|
+
encoding: {
|
|
678
|
+
x: { field: xField, title: xField, type: inferVegaType(normalizedRows, xField) }
|
|
679
|
+
},
|
|
680
|
+
layer: [
|
|
681
|
+
{
|
|
682
|
+
mark: "rule",
|
|
683
|
+
encoding: {
|
|
684
|
+
color,
|
|
685
|
+
tooltip: tooltip([xField, openField, highField, lowField, closeField]),
|
|
686
|
+
y: { field: lowField, title: "price", type: "quantitative" },
|
|
687
|
+
y2: { field: highField }
|
|
688
|
+
}
|
|
689
|
+
},
|
|
690
|
+
{
|
|
691
|
+
mark: "bar",
|
|
692
|
+
encoding: {
|
|
693
|
+
color,
|
|
694
|
+
y: { field: openField, title: "price", type: "quantitative" },
|
|
695
|
+
y2: { field: closeField }
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
],
|
|
699
|
+
title
|
|
700
|
+
},
|
|
701
|
+
xField,
|
|
702
|
+
yFields: [openField, highField, lowField, closeField]
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
function buildDepthSpec(input, rows, title) {
|
|
706
|
+
const priceField = requireField(
|
|
707
|
+
rows,
|
|
708
|
+
input.priceField ?? input.xField,
|
|
709
|
+
"priceField",
|
|
710
|
+
PRICE_FIELD_CANDIDATES
|
|
711
|
+
);
|
|
712
|
+
const sizeField = requireField(
|
|
713
|
+
rows,
|
|
714
|
+
input.sizeField ?? input.valueField ?? input.yFields?.[0],
|
|
715
|
+
"sizeField",
|
|
716
|
+
SIZE_FIELD_CANDIDATES
|
|
717
|
+
);
|
|
718
|
+
const sideField = requireField(
|
|
719
|
+
rows,
|
|
720
|
+
input.sideField ?? input.seriesField,
|
|
721
|
+
"sideField",
|
|
722
|
+
SIDE_FIELD_CANDIDATES
|
|
723
|
+
);
|
|
724
|
+
requireNumericField(rows, priceField, "priceField");
|
|
725
|
+
requireNumericField(rows, sizeField, "sizeField");
|
|
726
|
+
return {
|
|
727
|
+
spec: {
|
|
728
|
+
$schema: VEGA_SCHEMA,
|
|
729
|
+
data: { values: rows },
|
|
730
|
+
description: `xbbg market depth chart spec for ${input.source}`,
|
|
731
|
+
encoding: {
|
|
732
|
+
color: { field: sideField, title: sideField, type: "nominal" },
|
|
733
|
+
tooltip: tooltip([sideField, priceField, sizeField]),
|
|
734
|
+
x: { field: priceField, title: priceField, type: "quantitative" },
|
|
735
|
+
y: { field: sizeField, title: sizeField, type: "quantitative" }
|
|
736
|
+
},
|
|
737
|
+
mark: { type: "bar", tooltip: true },
|
|
738
|
+
title
|
|
739
|
+
},
|
|
740
|
+
xField: priceField,
|
|
741
|
+
yFields: [sizeField],
|
|
742
|
+
seriesField: sideField
|
|
743
|
+
};
|
|
744
|
+
}
|
|
745
|
+
function createChartSpec(input) {
|
|
746
|
+
const maxPoints = input.maxPoints ?? input.rows.length;
|
|
747
|
+
const rows = input.rows.length > maxPoints ? input.rows.slice(0, maxPoints) : input.rows;
|
|
748
|
+
if (rows.length === 0) {
|
|
749
|
+
throw new Error("rows must contain at least one chart data row");
|
|
750
|
+
}
|
|
751
|
+
const chart = input.chart ?? defaultChartForSource(input.source);
|
|
752
|
+
const title = input.title ?? `${input.source} ${chart}`;
|
|
753
|
+
const warnings = [];
|
|
754
|
+
if (rows.length !== input.rows.length) {
|
|
755
|
+
warnings.push(
|
|
756
|
+
`Chart spec contains first ${rows.length} of ${input.rows.length} rows; narrow the upstream request for a complete visualization.`
|
|
757
|
+
);
|
|
758
|
+
}
|
|
759
|
+
const built = chart === "candlestick" ? buildCandlestickSpec(input, rows, title) : chart === "depth" ? buildDepthSpec(input, rows, title) : chart === "bar" ? buildBarSpec(input, rows, title) : buildGenericSpec(input, rows, chart, title);
|
|
760
|
+
const summary = {
|
|
761
|
+
chart,
|
|
762
|
+
inputRows: input.rows.length,
|
|
763
|
+
renderer: "vega-lite",
|
|
764
|
+
rowCount: rows.length,
|
|
765
|
+
source: input.source,
|
|
766
|
+
title,
|
|
767
|
+
truncatedInput: rows.length !== input.rows.length,
|
|
768
|
+
xField: built.xField,
|
|
769
|
+
yFields: built.yFields,
|
|
770
|
+
...built.seriesField === void 0 ? {} : { seriesField: built.seriesField }
|
|
771
|
+
};
|
|
772
|
+
return {
|
|
773
|
+
kind: "xbbg.visualization",
|
|
774
|
+
version: 1,
|
|
775
|
+
component: COMPONENT_NAME,
|
|
776
|
+
renderer: "vega-lite",
|
|
777
|
+
rowCount: rows.length,
|
|
778
|
+
inputRowCount: input.rows.length,
|
|
779
|
+
truncatedInput: rows.length !== input.rows.length,
|
|
780
|
+
source: input.source,
|
|
781
|
+
chart,
|
|
782
|
+
summary,
|
|
783
|
+
spec: built.spec,
|
|
784
|
+
warnings
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
|
|
404
788
|
// src/cdx-fields.ts
|
|
405
789
|
var CDX_INFO_FIELDS = Object.freeze([
|
|
406
790
|
"ROLLING_SERIES",
|
|
@@ -492,6 +876,7 @@ var OPTIONAL_EXTENSION_INSTRUCTIONS = [
|
|
|
492
876
|
"- xbbg_ext_cdx: CDX ticker workflow support. Use parse_cdx_ticker to understand a CDX ticker, previous_cdx_series to roll back a series, cdx_gen_to_specific to resolve a generic CDX to a target series, and cdx_info/cdx_pricing/cdx_risk for predefined BDP field bundles. cdx_pricing and cdx_risk accept recoveryRate, which becomes the CDS_RR override.",
|
|
493
877
|
"- xbbg_ext_currency: currency-planning helpers. build_fx_pair constructs the Bloomberg FX pair and conversion factor, same_currency avoids unnecessary conversion, and currencies_needing_conversion identifies which currencies differ from a target before requesting converted values.",
|
|
494
878
|
"- xbbg_ext_bql_builder: safe BQL generators for common xbbg workflows. Use build_preferreds_query for preferred-stock discovery from an equity, build_corporate_bonds_query for company bond universes with optional currency/active filters, and build_etf_holdings_query for ETF constituents. Prefer these builders over hand-writing those BQL shapes.",
|
|
879
|
+
"- xbbg_ext_chart_spec: renderer-neutral chart spec helper. Convert bounded rows from xbbg_bdh, xbbg_bdib, holdings, depth, or already-shaped row data into a Vega-Lite JSON spec for frontend rendering; do not use it as proof that Bloomberg data was fetched.",
|
|
495
880
|
"- xbbg_ext_market_session: exchange calendar/timezone support. derive_sessions turns day session times into session blocks, infer_timezone maps country codes to timezones, session_times_to_utc converts local sessions to UTC, get_market_rule gets MIC/exchange rules, default_turnover_dates and default_bqr_datetimes provide bounded defaults, and get/list_exchange_override inspect configured exchange metadata.",
|
|
496
881
|
"- xbbg_ext_yas_overrides: builds flat YAS override maps for fixed-income BDP requests when the lower-level BDP workflow is required. Prefer xbbg_yas for actual YAS recipe fields.",
|
|
497
882
|
"- xbbg_ext_constants: static lookup/format helpers for date parsing/formatting, futures month code/name mappings, dividend type mappings, and known dividend/ETF output columns.",
|
|
@@ -503,7 +888,7 @@ var OPTIONAL_LIMIT_INSTRUCTIONS = [
|
|
|
503
888
|
"## Request limits and inputs",
|
|
504
889
|
"- Keep Bloomberg requests bounded: explicit securities, explicit fields, explicit dates, limited rows, and no broad exploratory pulls unless the user narrows the universe.",
|
|
505
890
|
"- Respect configured tool limits for securities, fields, rows, string size, BQL length, and search spec length. Ask the user to narrow the request rather than exceeding them.",
|
|
506
|
-
"- Use
|
|
891
|
+
"- Use primitive kwargs only: string, number, or boolean values. For overrides on xbbg_bdp/xbbg_bdh/xbbg_bds, use primitive values for global overrides and nested primitive maps keyed by exact security for per-security overrides. Do not send other nested objects, arrays, or inferred defaults."
|
|
507
892
|
];
|
|
508
893
|
var BLOOMBERG_TOOL_INSTRUCTIONS = [
|
|
509
894
|
...REQUIRED_TOOL_INSTRUCTIONS,
|
|
@@ -547,6 +932,7 @@ var EXT_FUTURES_DESCRIPTION = "Futures helpers for contract construction and sel
|
|
|
547
932
|
var EXT_CDX_DESCRIPTION = "CDX helpers for parsing, series rolling/resolution, and predefined info/pricing/risk BDP field bundles.";
|
|
548
933
|
var EXT_CURRENCY_DESCRIPTION = "Currency planning helpers: build FX pairs, test same-currency requests, and find currencies needing conversion.";
|
|
549
934
|
var EXT_BQL_BUILDER_DESCRIPTION = "BQL builders for preferred stocks, corporate bonds, and ETF holdings. Prefer to construct those bounded BQL shapes before xbbg_bql.";
|
|
935
|
+
var EXT_CHART_SPEC_DESCRIPTION = "Renderer-neutral chart spec helper for frontend generative UI. Converts bounded Bloomberg rows from bdh, bdib, holdings, depth, or already-shaped row data into a Vega-Lite JSON spec; it does not fetch Bloomberg data or render images.";
|
|
550
936
|
var EXT_MARKET_SESSION_DESCRIPTION = "Market session and timezone helpers for deriving sessions, UTC windows, market rules, exchange metadata, turnover defaults, and BQR datetime defaults.";
|
|
551
937
|
var EXT_YAS_OVERRIDES_DESCRIPTION = "Build flat Bloomberg YAS override maps for fixed-income analytics fields.";
|
|
552
938
|
var EXT_CONSTANTS_DESCRIPTION = "Static Bloomberg helper constants for date parsing/formatting, futures months, dividend types, and ETF/dividend columns.";
|
|
@@ -802,6 +1188,35 @@ function calculateSchema(options) {
|
|
|
802
1188
|
}
|
|
803
1189
|
});
|
|
804
1190
|
}
|
|
1191
|
+
function chartSpecSchema(options) {
|
|
1192
|
+
const chartScalar = z__namespace.union([
|
|
1193
|
+
z__namespace.string().trim().max(options.maxStringChars),
|
|
1194
|
+
z__namespace.number(),
|
|
1195
|
+
z__namespace.boolean(),
|
|
1196
|
+
z__namespace.null()
|
|
1197
|
+
]);
|
|
1198
|
+
const fieldName = nonEmptyString(options, "Input row field name.");
|
|
1199
|
+
return z__namespace.object({
|
|
1200
|
+
chart: z__namespace.enum(["line", "area", "bar", "scatter", "candlestick", "depth"]).optional().describe("Chart shape to generate. Defaults from source."),
|
|
1201
|
+
closeField: fieldName.optional().describe("Candlestick close-value field."),
|
|
1202
|
+
highField: fieldName.optional().describe("Candlestick high-value field."),
|
|
1203
|
+
labelField: fieldName.optional().describe("Categorical label field for bar charts."),
|
|
1204
|
+
lowField: fieldName.optional().describe("Candlestick low-value field."),
|
|
1205
|
+
maxPoints: z__namespace.number().int().positive().max(options.maxRows).optional().describe("Maximum rows to include in the frontend spec; defaults to all provided rows."),
|
|
1206
|
+
openField: fieldName.optional().describe("Candlestick open-value field."),
|
|
1207
|
+
priceField: fieldName.optional().describe("Market-depth price field."),
|
|
1208
|
+
renderer: z__namespace.literal("vega-lite").optional().describe("Visualization spec renderer. Currently only vega-lite is generated."),
|
|
1209
|
+
rows: z__namespace.array(z__namespace.record(chartScalar)).min(1).max(options.maxRows).describe("Chart data rows copied from a bounded Bloomberg tool result."),
|
|
1210
|
+
seriesField: fieldName.optional().describe("Optional series/color field."),
|
|
1211
|
+
sideField: fieldName.optional().describe("Market-depth bid/ask side field."),
|
|
1212
|
+
sizeField: fieldName.optional().describe("Market-depth size field."),
|
|
1213
|
+
source: z__namespace.enum(["bdh", "bdib", "holdings", "depth", "rows"]).describe("Bloomberg result shape that produced rows."),
|
|
1214
|
+
title: nonEmptyString(options, "Chart title.").optional(),
|
|
1215
|
+
valueField: fieldName.optional().describe("Primary numeric value field."),
|
|
1216
|
+
xField: fieldName.optional().describe("X-axis field."),
|
|
1217
|
+
yFields: stringArray(options, "Numeric value fields to plot.").optional()
|
|
1218
|
+
}).strict();
|
|
1219
|
+
}
|
|
805
1220
|
|
|
806
1221
|
// src/ext-tools.ts
|
|
807
1222
|
function resultString(resolver, name, value) {
|
|
@@ -816,6 +1231,7 @@ var EXT_TOOL_DEFINITIONS = Object.freeze([
|
|
|
816
1231
|
{ create: extCdxWithResolver, name: "xbbg_ext_cdx" },
|
|
817
1232
|
{ create: extCurrencyWithResolver, name: "xbbg_ext_currency" },
|
|
818
1233
|
{ create: extBqlBuilderWithResolver, name: "xbbg_ext_bql_builder" },
|
|
1234
|
+
{ create: extChartSpecWithResolver, name: "xbbg_ext_chart_spec" },
|
|
819
1235
|
{ create: extMarketSessionWithResolver, name: "xbbg_ext_market_session" },
|
|
820
1236
|
{ create: extYasOverridesWithResolver, name: "xbbg_ext_yas_overrides" },
|
|
821
1237
|
{ create: extConstantsWithResolver, name: "xbbg_ext_constants" },
|
|
@@ -825,6 +1241,24 @@ var EXT_TOOL_DEFINITIONS = Object.freeze([
|
|
|
825
1241
|
var BLOOMBERG_EXT_TOOL_NAMES = Object.freeze(
|
|
826
1242
|
EXT_TOOL_DEFINITIONS.map((definition) => definition.name)
|
|
827
1243
|
);
|
|
1244
|
+
function extChartSpecWithResolver(resolver) {
|
|
1245
|
+
const name = "xbbg_ext_chart_spec";
|
|
1246
|
+
return createBloombergStructuredTool(
|
|
1247
|
+
async (input) => {
|
|
1248
|
+
try {
|
|
1249
|
+
return await Promise.resolve(resultString(resolver, name, createChartSpec(input)));
|
|
1250
|
+
} catch (error) {
|
|
1251
|
+
throwWithToolContext(name, error);
|
|
1252
|
+
}
|
|
1253
|
+
},
|
|
1254
|
+
{
|
|
1255
|
+
responseFormat: "content_and_artifact",
|
|
1256
|
+
description: EXT_CHART_SPEC_DESCRIPTION,
|
|
1257
|
+
name,
|
|
1258
|
+
schema: chartSpecSchema(resolver.options)
|
|
1259
|
+
}
|
|
1260
|
+
);
|
|
1261
|
+
}
|
|
828
1262
|
function extTickerWithResolver(resolver) {
|
|
829
1263
|
const name = "xbbg_ext_ticker";
|
|
830
1264
|
return createBloombergStructuredTool(
|
|
@@ -1238,6 +1672,9 @@ function createExtColumnsTool(options = {}) {
|
|
|
1238
1672
|
function createExtCalculateTool(options = {}) {
|
|
1239
1673
|
return extCalculateWithResolver(createCoreResolver(options));
|
|
1240
1674
|
}
|
|
1675
|
+
function createExtChartSpecTool(options = {}) {
|
|
1676
|
+
return extChartSpecWithResolver(createCoreResolver(options));
|
|
1677
|
+
}
|
|
1241
1678
|
function createBloombergExtToolsForResolver(resolver) {
|
|
1242
1679
|
return EXT_TOOL_DEFINITIONS.filter(
|
|
1243
1680
|
(definition) => !isToolDisabled(resolver.options, definition.name)
|
|
@@ -1383,6 +1820,60 @@ function primitiveMap(tool2, field) {
|
|
|
1383
1820
|
return normalized;
|
|
1384
1821
|
});
|
|
1385
1822
|
}
|
|
1823
|
+
function overridesMap(tool2, field) {
|
|
1824
|
+
return z__namespace.record(
|
|
1825
|
+
z__namespace.string().min(1),
|
|
1826
|
+
z__namespace.union([primitiveSchema, z__namespace.record(z__namespace.string().min(1), primitiveSchema)])
|
|
1827
|
+
).optional().transform((value, context) => {
|
|
1828
|
+
if (value === void 0) {
|
|
1829
|
+
return void 0;
|
|
1830
|
+
}
|
|
1831
|
+
const normalized = {};
|
|
1832
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
1833
|
+
const normalizedKey = key.trim();
|
|
1834
|
+
if (normalizedKey.length === 0) {
|
|
1835
|
+
return normalizationIssue(context, tool2, field, new TypeError("contains an empty key"));
|
|
1836
|
+
}
|
|
1837
|
+
if (typeof entry !== "object") {
|
|
1838
|
+
if (typeof entry === "string" && entry.length === 0) {
|
|
1839
|
+
return normalizationIssue(
|
|
1840
|
+
context,
|
|
1841
|
+
tool2,
|
|
1842
|
+
field,
|
|
1843
|
+
new TypeError(`${normalizedKey} must not be an empty string`)
|
|
1844
|
+
);
|
|
1845
|
+
}
|
|
1846
|
+
normalized[normalizedKey] = entry;
|
|
1847
|
+
continue;
|
|
1848
|
+
}
|
|
1849
|
+
const normalizedOverrides = {};
|
|
1850
|
+
for (const [overrideKey, overrideValue] of Object.entries(entry)) {
|
|
1851
|
+
const normalizedOverrideKey = overrideKey.trim();
|
|
1852
|
+
if (normalizedOverrideKey.length === 0) {
|
|
1853
|
+
return normalizationIssue(
|
|
1854
|
+
context,
|
|
1855
|
+
tool2,
|
|
1856
|
+
field,
|
|
1857
|
+
new TypeError(`${normalizedKey} contains an empty override key`)
|
|
1858
|
+
);
|
|
1859
|
+
}
|
|
1860
|
+
if (typeof overrideValue === "string" && overrideValue.length === 0) {
|
|
1861
|
+
return normalizationIssue(
|
|
1862
|
+
context,
|
|
1863
|
+
tool2,
|
|
1864
|
+
field,
|
|
1865
|
+
new TypeError(
|
|
1866
|
+
`${normalizedKey}.${normalizedOverrideKey} must not be an empty string`
|
|
1867
|
+
)
|
|
1868
|
+
);
|
|
1869
|
+
}
|
|
1870
|
+
normalizedOverrides[normalizedOverrideKey] = overrideValue;
|
|
1871
|
+
}
|
|
1872
|
+
normalized[normalizedKey] = normalizedOverrides;
|
|
1873
|
+
}
|
|
1874
|
+
return normalized;
|
|
1875
|
+
});
|
|
1876
|
+
}
|
|
1386
1877
|
function dateField(tool2, field) {
|
|
1387
1878
|
return z__namespace.union([z__namespace.string(), z__namespace.number()]).transform((value, context) => {
|
|
1388
1879
|
try {
|
|
@@ -1445,8 +1936,8 @@ function createBdpSchema(options) {
|
|
|
1445
1936
|
kwargs: primitiveMap(tool2, "kwargs").describe(
|
|
1446
1937
|
"Advanced Bloomberg request kwargs as flat string/number/boolean values only."
|
|
1447
1938
|
),
|
|
1448
|
-
overrides:
|
|
1449
|
-
"Bloomberg field overrides
|
|
1939
|
+
overrides: overridesMap(tool2, "overrides").describe(
|
|
1940
|
+
"Bloomberg field overrides. Use primitive values for global overrides and nested primitive maps keyed by exact security for per-security overrides."
|
|
1450
1941
|
),
|
|
1451
1942
|
securities: stringArray2(
|
|
1452
1943
|
tool2,
|
|
@@ -1477,8 +1968,8 @@ function createBdhSchema(options) {
|
|
|
1477
1968
|
kwargs: primitiveMap(tool2, "kwargs").describe(
|
|
1478
1969
|
"Advanced Bloomberg request kwargs as flat string/number/boolean values only."
|
|
1479
1970
|
),
|
|
1480
|
-
overrides:
|
|
1481
|
-
"Bloomberg overrides
|
|
1971
|
+
overrides: overridesMap(tool2, "overrides").describe(
|
|
1972
|
+
"Bloomberg overrides. Use primitive values for global overrides and nested primitive maps keyed by exact security for per-security overrides."
|
|
1482
1973
|
),
|
|
1483
1974
|
securities: stringArray2(
|
|
1484
1975
|
tool2,
|
|
@@ -1510,8 +2001,8 @@ function createBdsSchema(options) {
|
|
|
1510
2001
|
kwargs: primitiveMap(tool2, "kwargs").describe(
|
|
1511
2002
|
"Advanced Bloomberg request kwargs as flat string/number/boolean values only."
|
|
1512
2003
|
),
|
|
1513
|
-
overrides:
|
|
1514
|
-
"Bloomberg overrides
|
|
2004
|
+
overrides: overridesMap(tool2, "overrides").describe(
|
|
2005
|
+
"Bloomberg overrides. Use primitive values for global overrides and nested primitive maps keyed by exact security for per-security overrides."
|
|
1515
2006
|
),
|
|
1516
2007
|
securities: stringArray2(
|
|
1517
2008
|
tool2,
|
|
@@ -1731,7 +2222,7 @@ function createPreferredsSchema(options) {
|
|
|
1731
2222
|
).describe(
|
|
1732
2223
|
"The issuer's common equity ticker as '<TICKER> <MARKET_SECTOR>', never a preferred ('Pfd') ticker and never a guessed one. Resolve a supplied ISIN/CUSIP with xbbg_resolve_isins first."
|
|
1733
2224
|
),
|
|
1734
|
-
fields:
|
|
2225
|
+
fields: z__namespace.array(nonEmptyString2(tool2, "fields", options.maxStringChars, '["<FIELD>"]')).max(options.maxFields, `${tool2}: fields can contain at most ${options.maxFields} values`).transform((fields) => fields.length === 0 ? void 0 : fields).optional().describe("Optional fields to include in the preferreds recipe result.")
|
|
1735
2226
|
});
|
|
1736
2227
|
}
|
|
1737
2228
|
function createCorporateBondsSchema(options) {
|
|
@@ -2051,14 +2542,15 @@ function bdpWithResolver(resolver) {
|
|
|
2051
2542
|
async (input) => {
|
|
2052
2543
|
try {
|
|
2053
2544
|
const engine = await resolver.getEngine();
|
|
2054
|
-
const
|
|
2545
|
+
const options = {
|
|
2055
2546
|
backend: "json",
|
|
2056
2547
|
format: input.format,
|
|
2057
2548
|
includeSecurityErrors: input.includeSecurityErrors,
|
|
2058
2549
|
kwargs: input.kwargs,
|
|
2059
2550
|
overrides: input.overrides,
|
|
2060
2551
|
validateFields: validationSetting(resolver, input.validateFields)
|
|
2061
|
-
}
|
|
2552
|
+
};
|
|
2553
|
+
const result = await engine.bdp(input.securities, input.fields, options);
|
|
2062
2554
|
return resultString2(resolver, name, result);
|
|
2063
2555
|
} catch (error) {
|
|
2064
2556
|
throwWithToolContext(name, error);
|
|
@@ -2078,7 +2570,7 @@ function bdhWithResolver(resolver) {
|
|
|
2078
2570
|
async (input) => {
|
|
2079
2571
|
try {
|
|
2080
2572
|
const engine = await resolver.getEngine();
|
|
2081
|
-
const
|
|
2573
|
+
const options = {
|
|
2082
2574
|
backend: "json",
|
|
2083
2575
|
end: input.end,
|
|
2084
2576
|
format: input.format,
|
|
@@ -2086,7 +2578,8 @@ function bdhWithResolver(resolver) {
|
|
|
2086
2578
|
overrides: input.overrides,
|
|
2087
2579
|
start: input.start,
|
|
2088
2580
|
validateFields: validationSetting(resolver, input.validateFields)
|
|
2089
|
-
}
|
|
2581
|
+
};
|
|
2582
|
+
const result = await engine.bdh(input.securities, input.fields, options);
|
|
2090
2583
|
return resultString2(resolver, name, result);
|
|
2091
2584
|
} catch (error) {
|
|
2092
2585
|
throwWithToolContext(name, error);
|
|
@@ -2106,12 +2599,13 @@ function bdsWithResolver(resolver) {
|
|
|
2106
2599
|
async (input) => {
|
|
2107
2600
|
try {
|
|
2108
2601
|
const engine = await resolver.getEngine();
|
|
2109
|
-
const
|
|
2602
|
+
const options = {
|
|
2110
2603
|
backend: "json",
|
|
2111
2604
|
kwargs: input.kwargs,
|
|
2112
2605
|
overrides: input.overrides,
|
|
2113
2606
|
validateFields: validationSetting(resolver, input.validateFields)
|
|
2114
|
-
}
|
|
2607
|
+
};
|
|
2608
|
+
const result = await engine.bds(input.securities, [input.field], options);
|
|
2115
2609
|
return resultString2(resolver, name, result);
|
|
2116
2610
|
} catch (error) {
|
|
2117
2611
|
throwWithToolContext(name, error);
|
|
@@ -2669,6 +3163,7 @@ exports.createEtfHoldingsTool = createEtfHoldingsTool;
|
|
|
2669
3163
|
exports.createExtBqlBuilderTool = createExtBqlBuilderTool;
|
|
2670
3164
|
exports.createExtCalculateTool = createExtCalculateTool;
|
|
2671
3165
|
exports.createExtCdxTool = createExtCdxTool;
|
|
3166
|
+
exports.createExtChartSpecTool = createExtChartSpecTool;
|
|
2672
3167
|
exports.createExtColumnsTool = createExtColumnsTool;
|
|
2673
3168
|
exports.createExtConstantsTool = createExtConstantsTool;
|
|
2674
3169
|
exports.createExtCurrencyTool = createExtCurrencyTool;
|