@nhtio/adk 0.1.0-master-f0aa531d
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/LICENSE.md +9 -0
- package/README.md +3 -0
- package/batteries/index.d.ts +28 -0
- package/batteries/llm/index.d.ts +11 -0
- package/batteries/llm/openai_chat_completions/adapter.cjs +916 -0
- package/batteries/llm/openai_chat_completions/adapter.cjs.map +1 -0
- package/batteries/llm/openai_chat_completions/adapter.d.ts +101 -0
- package/batteries/llm/openai_chat_completions/adapter.mjs +914 -0
- package/batteries/llm/openai_chat_completions/adapter.mjs.map +1 -0
- package/batteries/llm/openai_chat_completions/exceptions.cjs +89 -0
- package/batteries/llm/openai_chat_completions/exceptions.cjs.map +1 -0
- package/batteries/llm/openai_chat_completions/exceptions.d.ts +97 -0
- package/batteries/llm/openai_chat_completions/exceptions.mjs +81 -0
- package/batteries/llm/openai_chat_completions/exceptions.mjs.map +1 -0
- package/batteries/llm/openai_chat_completions/helpers.cjs +819 -0
- package/batteries/llm/openai_chat_completions/helpers.cjs.map +1 -0
- package/batteries/llm/openai_chat_completions/helpers.d.ts +233 -0
- package/batteries/llm/openai_chat_completions/helpers.mjs +783 -0
- package/batteries/llm/openai_chat_completions/helpers.mjs.map +1 -0
- package/batteries/llm/openai_chat_completions/index.d.ts +27 -0
- package/batteries/llm/openai_chat_completions/types.cjs +1 -0
- package/batteries/llm/openai_chat_completions/types.d.ts +524 -0
- package/batteries/llm/openai_chat_completions/types.mjs +0 -0
- package/batteries/llm/openai_chat_completions/validation.cjs +190 -0
- package/batteries/llm/openai_chat_completions/validation.cjs.map +1 -0
- package/batteries/llm/openai_chat_completions/validation.d.ts +31 -0
- package/batteries/llm/openai_chat_completions/validation.mjs +187 -0
- package/batteries/llm/openai_chat_completions/validation.mjs.map +1 -0
- package/batteries/llm/openai_chat_completions.cjs +51 -0
- package/batteries/llm/openai_chat_completions.mjs +5 -0
- package/batteries/llm/webllm_chat_completions/adapter.cjs +658 -0
- package/batteries/llm/webllm_chat_completions/adapter.cjs.map +1 -0
- package/batteries/llm/webllm_chat_completions/adapter.d.ts +103 -0
- package/batteries/llm/webllm_chat_completions/adapter.mjs +656 -0
- package/batteries/llm/webllm_chat_completions/adapter.mjs.map +1 -0
- package/batteries/llm/webllm_chat_completions/exceptions.cjs +70 -0
- package/batteries/llm/webllm_chat_completions/exceptions.cjs.map +1 -0
- package/batteries/llm/webllm_chat_completions/exceptions.d.ts +74 -0
- package/batteries/llm/webllm_chat_completions/exceptions.mjs +65 -0
- package/batteries/llm/webllm_chat_completions/exceptions.mjs.map +1 -0
- package/batteries/llm/webllm_chat_completions/helpers.cjs +38 -0
- package/batteries/llm/webllm_chat_completions/helpers.d.ts +6 -0
- package/batteries/llm/webllm_chat_completions/helpers.mjs +2 -0
- package/batteries/llm/webllm_chat_completions/index.d.ts +25 -0
- package/batteries/llm/webllm_chat_completions/types.d.ts +31 -0
- package/batteries/llm/webllm_chat_completions/validation.cjs +115 -0
- package/batteries/llm/webllm_chat_completions/validation.cjs.map +1 -0
- package/batteries/llm/webllm_chat_completions/validation.d.ts +8 -0
- package/batteries/llm/webllm_chat_completions/validation.mjs +112 -0
- package/batteries/llm/webllm_chat_completions/validation.mjs.map +1 -0
- package/batteries/llm/webllm_chat_completions.cjs +50 -0
- package/batteries/llm/webllm_chat_completions.mjs +6 -0
- package/batteries/llm.cjs +63 -0
- package/batteries/llm.mjs +10 -0
- package/batteries/storage/flydrive/index.d.ts +167 -0
- package/batteries/storage/flydrive.cjs +249 -0
- package/batteries/storage/flydrive.cjs.map +1 -0
- package/batteries/storage/flydrive.mjs +249 -0
- package/batteries/storage/flydrive.mjs.map +1 -0
- package/batteries/storage/in_memory/index.d.ts +106 -0
- package/batteries/storage/in_memory.cjs +121 -0
- package/batteries/storage/in_memory.cjs.map +1 -0
- package/batteries/storage/in_memory.mjs +119 -0
- package/batteries/storage/in_memory.mjs.map +1 -0
- package/batteries/storage/index.d.ts +18 -0
- package/batteries/storage/opfs/index.d.ts +299 -0
- package/batteries/storage/opfs.cjs +368 -0
- package/batteries/storage/opfs.cjs.map +1 -0
- package/batteries/storage/opfs.mjs +366 -0
- package/batteries/storage/opfs.mjs.map +1 -0
- package/batteries/storage.cjs +4 -0
- package/batteries/storage.mjs +2 -0
- package/batteries/tools/color/index.d.ts +37 -0
- package/batteries/tools/color.cjs +659 -0
- package/batteries/tools/color.cjs.map +1 -0
- package/batteries/tools/color.mjs +655 -0
- package/batteries/tools/color.mjs.map +1 -0
- package/batteries/tools/comparison/index.d.ts +29 -0
- package/batteries/tools/comparison.cjs +171 -0
- package/batteries/tools/comparison.cjs.map +1 -0
- package/batteries/tools/comparison.mjs +168 -0
- package/batteries/tools/comparison.mjs.map +1 -0
- package/batteries/tools/data_structure/index.d.ts +30 -0
- package/batteries/tools/data_structure.cjs +270 -0
- package/batteries/tools/data_structure.cjs.map +1 -0
- package/batteries/tools/data_structure.mjs +267 -0
- package/batteries/tools/data_structure.mjs.map +1 -0
- package/batteries/tools/datetime_extended/index.d.ts +51 -0
- package/batteries/tools/datetime_extended.cjs +309 -0
- package/batteries/tools/datetime_extended.cjs.map +1 -0
- package/batteries/tools/datetime_extended.mjs +302 -0
- package/batteries/tools/datetime_extended.mjs.map +1 -0
- package/batteries/tools/datetime_math/index.d.ts +36 -0
- package/batteries/tools/datetime_math.cjs +175 -0
- package/batteries/tools/datetime_math.cjs.map +1 -0
- package/batteries/tools/datetime_math.mjs +171 -0
- package/batteries/tools/datetime_math.mjs.map +1 -0
- package/batteries/tools/encoding/index.d.ts +36 -0
- package/batteries/tools/encoding.cjs +156 -0
- package/batteries/tools/encoding.cjs.map +1 -0
- package/batteries/tools/encoding.mjs +152 -0
- package/batteries/tools/encoding.mjs.map +1 -0
- package/batteries/tools/formatting/index.d.ts +28 -0
- package/batteries/tools/formatting.cjs +120 -0
- package/batteries/tools/formatting.cjs.map +1 -0
- package/batteries/tools/formatting.mjs +117 -0
- package/batteries/tools/formatting.mjs.map +1 -0
- package/batteries/tools/geo_basics/index.d.ts +33 -0
- package/batteries/tools/geo_basics.cjs +136 -0
- package/batteries/tools/geo_basics.cjs.map +1 -0
- package/batteries/tools/geo_basics.mjs +132 -0
- package/batteries/tools/geo_basics.mjs.map +1 -0
- package/batteries/tools/index.d.ts +32 -0
- package/batteries/tools/math/index.d.ts +37 -0
- package/batteries/tools/math.cjs +136 -0
- package/batteries/tools/math.cjs.map +1 -0
- package/batteries/tools/math.mjs +133 -0
- package/batteries/tools/math.mjs.map +1 -0
- package/batteries/tools/memory/index.d.ts +73 -0
- package/batteries/tools/memory.cjs +193 -0
- package/batteries/tools/memory.cjs.map +1 -0
- package/batteries/tools/memory.mjs +187 -0
- package/batteries/tools/memory.mjs.map +1 -0
- package/batteries/tools/parsing/index.d.ts +47 -0
- package/batteries/tools/parsing.cjs +191 -0
- package/batteries/tools/parsing.cjs.map +1 -0
- package/batteries/tools/parsing.mjs +185 -0
- package/batteries/tools/parsing.mjs.map +1 -0
- package/batteries/tools/retrievables/index.d.ts +81 -0
- package/batteries/tools/retrievables.cjs +215 -0
- package/batteries/tools/retrievables.cjs.map +1 -0
- package/batteries/tools/retrievables.mjs +209 -0
- package/batteries/tools/retrievables.mjs.map +1 -0
- package/batteries/tools/standing_instructions/index.d.ts +64 -0
- package/batteries/tools/standing_instructions.cjs +126 -0
- package/batteries/tools/standing_instructions.cjs.map +1 -0
- package/batteries/tools/standing_instructions.mjs +121 -0
- package/batteries/tools/standing_instructions.mjs.map +1 -0
- package/batteries/tools/statistics/index.d.ts +46 -0
- package/batteries/tools/statistics.cjs +253 -0
- package/batteries/tools/statistics.cjs.map +1 -0
- package/batteries/tools/statistics.mjs +248 -0
- package/batteries/tools/statistics.mjs.map +1 -0
- package/batteries/tools/string_processing/index.d.ts +29 -0
- package/batteries/tools/string_processing.cjs +154 -0
- package/batteries/tools/string_processing.cjs.map +1 -0
- package/batteries/tools/string_processing.mjs +151 -0
- package/batteries/tools/string_processing.mjs.map +1 -0
- package/batteries/tools/structured_data/index.d.ts +34 -0
- package/batteries/tools/structured_data.cjs +189 -0
- package/batteries/tools/structured_data.cjs.map +1 -0
- package/batteries/tools/structured_data.mjs +185 -0
- package/batteries/tools/structured_data.mjs.map +1 -0
- package/batteries/tools/text_analysis/index.d.ts +31 -0
- package/batteries/tools/text_analysis.cjs +120 -0
- package/batteries/tools/text_analysis.cjs.map +1 -0
- package/batteries/tools/text_analysis.mjs +117 -0
- package/batteries/tools/text_analysis.mjs.map +1 -0
- package/batteries/tools/text_comparison/index.d.ts +28 -0
- package/batteries/tools/text_comparison.cjs +96 -0
- package/batteries/tools/text_comparison.cjs.map +1 -0
- package/batteries/tools/text_comparison.mjs +93 -0
- package/batteries/tools/text_comparison.mjs.map +1 -0
- package/batteries/tools/time/index.d.ts +27 -0
- package/batteries/tools/time.cjs +63 -0
- package/batteries/tools/time.cjs.map +1 -0
- package/batteries/tools/time.mjs +60 -0
- package/batteries/tools/time.mjs.map +1 -0
- package/batteries/tools/unit_conversion/index.d.ts +19 -0
- package/batteries/tools/unit_conversion.cjs +452 -0
- package/batteries/tools/unit_conversion.cjs.map +1 -0
- package/batteries/tools/unit_conversion.mjs +450 -0
- package/batteries/tools/unit_conversion.mjs.map +1 -0
- package/batteries/tools.cjs +80 -0
- package/batteries/tools.mjs +21 -0
- package/batteries.cjs +142 -0
- package/batteries.mjs +30 -0
- package/chunk-KmRHZBOW.js +35 -0
- package/common-DeZaonK1.mjs +208 -0
- package/common-DeZaonK1.mjs.map +1 -0
- package/common-Od8edUXU.js +232 -0
- package/common-Od8edUXU.js.map +1 -0
- package/common.cjs +31 -0
- package/common.d.ts +108 -0
- package/common.mjs +8 -0
- package/dispatch_runner-9j6bXHL3.mjs +1609 -0
- package/dispatch_runner-9j6bXHL3.mjs.map +1 -0
- package/dispatch_runner-CsoH0nld.js +1627 -0
- package/dispatch_runner-CsoH0nld.js.map +1 -0
- package/dispatch_runner.cjs +3 -0
- package/dispatch_runner.d.ts +17 -0
- package/dispatch_runner.mjs +2 -0
- package/exceptions-D5YrO9Vm.js +280 -0
- package/exceptions-D5YrO9Vm.js.map +1 -0
- package/exceptions-NrzIHw_R.mjs +244 -0
- package/exceptions-NrzIHw_R.mjs.map +1 -0
- package/exceptions.cjs +33 -0
- package/exceptions.d.ts +52 -0
- package/exceptions.mjs +3 -0
- package/factories.cjs +4 -0
- package/factories.d.ts +39 -0
- package/factories.mjs +2 -0
- package/forge.cjs +9 -0
- package/forge.d.ts +49 -0
- package/forge.mjs +5 -0
- package/guards.cjs +96 -0
- package/guards.cjs.map +1 -0
- package/guards.d.ts +83 -0
- package/guards.mjs +72 -0
- package/guards.mjs.map +1 -0
- package/index.cjs +107 -0
- package/index.cjs.map +1 -0
- package/index.d.ts +18 -0
- package/index.mjs +31 -0
- package/index.mjs.map +1 -0
- package/lib/classes/artifact_tool.d.ts +129 -0
- package/lib/classes/base_exception.d.ts +83 -0
- package/lib/classes/identity.d.ts +71 -0
- package/lib/classes/media.d.ts +326 -0
- package/lib/classes/memory.d.ts +72 -0
- package/lib/classes/message.d.ts +137 -0
- package/lib/classes/registry.d.ts +79 -0
- package/lib/classes/retrievable.d.ts +100 -0
- package/lib/classes/spooled_artifact.d.ts +296 -0
- package/lib/classes/spooled_json_artifact.d.ts +158 -0
- package/lib/classes/spooled_markdown_artifact.d.ts +202 -0
- package/lib/classes/thought.d.ts +142 -0
- package/lib/classes/tokenizable.d.ts +124 -0
- package/lib/classes/tool.d.ts +228 -0
- package/lib/classes/tool_call.d.ts +190 -0
- package/lib/classes/tool_registry.d.ts +159 -0
- package/lib/classes/turn_gate.d.ts +109 -0
- package/lib/contracts/dispatch_context.d.ts +345 -0
- package/lib/contracts/media_reader.d.ts +60 -0
- package/lib/contracts/spool_reader.d.ts +80 -0
- package/lib/contracts/spooled_artifact_constructor.d.ts +38 -0
- package/lib/contracts/turn_runner_config.d.ts +101 -0
- package/lib/contracts/turn_runner_context.d.ts +267 -0
- package/lib/dispatch_runner.d.ts +98 -0
- package/lib/exceptions/runtime.d.ts +370 -0
- package/lib/helpers/media_readers.d.ts +39 -0
- package/lib/turn_runner.d.ts +144 -0
- package/lib/types/dispatch_context.d.ts +233 -0
- package/lib/types/dispatch_runner.d.ts +387 -0
- package/lib/types/turn_runner.d.ts +322 -0
- package/lib/utils/canonical_json.d.ts +18 -0
- package/lib/utils/exceptions.d.ts +78 -0
- package/lib/utils/guards.d.ts +32 -0
- package/lib/utils/validation.d.ts +77 -0
- package/package.json +334 -0
- package/runtime-BJVkrGQe.js +519 -0
- package/runtime-BJVkrGQe.js.map +1 -0
- package/runtime-CrEPIFgr.mjs +346 -0
- package/runtime-CrEPIFgr.mjs.map +1 -0
- package/skills/adk-assembly/SKILL.md +109 -0
- package/skills/adk-assembly/references/assembly-contract.md +66 -0
- package/skills/adk-assembly/references/executors-tools-pipelines-events.md +113 -0
- package/skills/adk-assembly/references/first-integration.md +93 -0
- package/skills/adk-assembly/references/storage-and-context.md +102 -0
- package/spooled_artifact-C5ZtGxuJ.mjs +544 -0
- package/spooled_artifact-C5ZtGxuJ.mjs.map +1 -0
- package/spooled_artifact-Cm9Te22K.js +568 -0
- package/spooled_artifact-Cm9Te22K.js.map +1 -0
- package/spooled_artifact.cjs +7 -0
- package/spooled_artifact.d.ts +40 -0
- package/spooled_artifact.mjs +3 -0
- package/spooled_markdown_artifact-BpUJol0W.mjs +771 -0
- package/spooled_markdown_artifact-BpUJol0W.mjs.map +1 -0
- package/spooled_markdown_artifact-RRB113sy.js +786 -0
- package/spooled_markdown_artifact-RRB113sy.js.map +1 -0
- package/thought-CDb457b4.mjs +470 -0
- package/thought-CDb457b4.mjs.map +1 -0
- package/thought-DuN2PgdO.js +494 -0
- package/thought-DuN2PgdO.js.map +1 -0
- package/tool-COSeH8I6.js +302 -0
- package/tool-COSeH8I6.js.map +1 -0
- package/tool-D2WB1EA1.mjs +296 -0
- package/tool-D2WB1EA1.mjs.map +1 -0
- package/tool_call-BKyyxGaZ.mjs +578 -0
- package/tool_call-BKyyxGaZ.mjs.map +1 -0
- package/tool_call-DFgzcVcU.js +608 -0
- package/tool_call-DFgzcVcU.js.map +1 -0
- package/tool_registry-Dkfprsck.js +641 -0
- package/tool_registry-Dkfprsck.js.map +1 -0
- package/tool_registry-DqLOyGyG.mjs +592 -0
- package/tool_registry-DqLOyGyG.mjs.map +1 -0
- package/turn_runner-CMm2BHdX.js +615 -0
- package/turn_runner-CMm2BHdX.js.map +1 -0
- package/turn_runner-y7eyEcJH.mjs +603 -0
- package/turn_runner-y7eyEcJH.mjs.map +1 -0
- package/turn_runner.cjs +3 -0
- package/turn_runner.d.ts +21 -0
- package/turn_runner.mjs +2 -0
- package/types.cjs +1 -0
- package/types.d.ts +56 -0
- package/types.mjs +0 -0
- package/vite-env.d.ts +23 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
require("../../chunk-KmRHZBOW.js");
|
|
3
|
+
const require_tool_registry = require("../../tool_registry-Dkfprsck.js");
|
|
4
|
+
require("../../common-Od8edUXU.js");
|
|
5
|
+
const require_tool = require("../../tool-COSeH8I6.js");
|
|
6
|
+
require("../../guards.cjs");
|
|
7
|
+
let _nhtio_validation = require("@nhtio/validation");
|
|
8
|
+
//#region src/batteries/tools/formatting/index.ts
|
|
9
|
+
/**
|
|
10
|
+
* Pre-constructed tools for locale-aware number, list, table, and text formatting.
|
|
11
|
+
*
|
|
12
|
+
* @module @nhtio/adk/batteries/tools/formatting
|
|
13
|
+
*
|
|
14
|
+
* @remarks
|
|
15
|
+
* Pre-constructed bundled tools for the `formatting` category. Import individually, the whole
|
|
16
|
+
* category, or import every tool via `@nhtio/adk/batteries`.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Format a number using locale-aware styles.
|
|
20
|
+
*
|
|
21
|
+
* @remarks
|
|
22
|
+
* Supported styles: `decimal`, `currency`, `percent`, `compact` (e.g. `1.2K`), `scientific`
|
|
23
|
+
* (e.g. `1.2e+3`), and `ordinal` (`1st`, `2nd`, `3rd`). Uses `Intl.NumberFormat` and
|
|
24
|
+
* `Intl.PluralRules` from the JS standard library. Returns an error string for non-finite values
|
|
25
|
+
* or invalid currency-without-currency-code.
|
|
26
|
+
*/
|
|
27
|
+
var formatNumberTool = new require_tool.Tool({
|
|
28
|
+
name: "format_number",
|
|
29
|
+
description: "Format a number using locale-aware styles: decimal, currency, percent, compact (1.2K), scientific (1.2e3), or ordinal (1st/2nd/3rd). Supports locale and precision options.",
|
|
30
|
+
inputSchema: _nhtio_validation.validator.object({
|
|
31
|
+
value: _nhtio_validation.validator.number().required().description("The number to format"),
|
|
32
|
+
style: _nhtio_validation.validator.string().valid("decimal", "currency", "percent", "compact", "scientific", "ordinal").default("decimal").description("Formatting style (default: decimal)"),
|
|
33
|
+
currency: _nhtio_validation.validator.string().optional().description("ISO 4217 currency code — required when style is \"currency\" (e.g. \"USD\", \"EUR\")"),
|
|
34
|
+
locale: _nhtio_validation.validator.string().default("en-US").description("BCP 47 locale tag (default: \"en-US\")"),
|
|
35
|
+
min_decimals: _nhtio_validation.validator.number().optional().description("Minimum fraction digits (default: style-dependent)"),
|
|
36
|
+
max_decimals: _nhtio_validation.validator.number().optional().description("Maximum fraction digits (default: style-dependent)")
|
|
37
|
+
}),
|
|
38
|
+
handler: async (args) => {
|
|
39
|
+
const { value, style, locale, currency, min_decimals: minDec, max_decimals: maxDec } = args;
|
|
40
|
+
if (!Number.isFinite(value)) return `Error: Value must be a finite number (got ${value}).`;
|
|
41
|
+
try {
|
|
42
|
+
if (style === "ordinal") {
|
|
43
|
+
const suffix = {
|
|
44
|
+
one: "st",
|
|
45
|
+
two: "nd",
|
|
46
|
+
few: "rd",
|
|
47
|
+
other: "th"
|
|
48
|
+
}[new Intl.PluralRules(locale, { type: "ordinal" }).select(value)] ?? "th";
|
|
49
|
+
return `${new Intl.NumberFormat(locale).format(value)}${suffix}`;
|
|
50
|
+
}
|
|
51
|
+
if (style === "scientific") {
|
|
52
|
+
const exp = value === 0 ? 0 : Math.floor(Math.log10(Math.abs(value)));
|
|
53
|
+
const mantissa = value / Math.pow(10, exp);
|
|
54
|
+
return `${new Intl.NumberFormat(locale, {
|
|
55
|
+
minimumFractionDigits: minDec ?? 2,
|
|
56
|
+
maximumFractionDigits: maxDec ?? 6
|
|
57
|
+
}).format(mantissa)}e${exp >= 0 ? "+" : ""}${exp}`;
|
|
58
|
+
}
|
|
59
|
+
const opts = {};
|
|
60
|
+
if (style === "currency") {
|
|
61
|
+
if (!currency) return "Error: \"currency\" parameter is required when style is \"currency\".";
|
|
62
|
+
opts.style = "currency";
|
|
63
|
+
opts.currency = currency.toUpperCase();
|
|
64
|
+
} else if (style === "percent") {
|
|
65
|
+
opts.style = "percent";
|
|
66
|
+
opts.minimumFractionDigits = minDec ?? 1;
|
|
67
|
+
opts.maximumFractionDigits = maxDec ?? 2;
|
|
68
|
+
} else if (style === "compact") {
|
|
69
|
+
opts.notation = "compact";
|
|
70
|
+
opts.compactDisplay = "short";
|
|
71
|
+
} else opts.style = "decimal";
|
|
72
|
+
if (minDec !== void 0 && style !== "percent") opts.minimumFractionDigits = minDec;
|
|
73
|
+
if (maxDec !== void 0 && style !== "percent") opts.maximumFractionDigits = maxDec;
|
|
74
|
+
return new Intl.NumberFormat(locale, opts).format(value);
|
|
75
|
+
} catch (err) {
|
|
76
|
+
return `Error: ${require_tool_registry.isError(err) ? err.message : String(err)}`;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
/**
|
|
81
|
+
* Format an array of items as a list.
|
|
82
|
+
*
|
|
83
|
+
* @remarks
|
|
84
|
+
* Supported styles: `bullet` (`• item`), `numbered` (`1. item`), `inline_and`
|
|
85
|
+
* (`a, b, and c`), `inline_or` (`a, b, or c`), `newline` (one per line).
|
|
86
|
+
*/
|
|
87
|
+
var formatListTool = new require_tool.Tool({
|
|
88
|
+
name: "format_list",
|
|
89
|
+
description: "Format an array of items as a list. Styles: bullet (• item), numbered (1. item), inline_and (\"a, b, and c\"), inline_or (\"a, b, or c\"), newline (one per line).",
|
|
90
|
+
inputSchema: _nhtio_validation.validator.object({
|
|
91
|
+
items: _nhtio_validation.validator.array().items(_nhtio_validation.validator.string()).required().description("Array of items to format"),
|
|
92
|
+
style: _nhtio_validation.validator.string().valid("bullet", "numbered", "inline_and", "inline_or", "newline").default("bullet").description("List format style (default: bullet)"),
|
|
93
|
+
indent: _nhtio_validation.validator.number().default(0).description("Spaces to indent each item (default: 0)")
|
|
94
|
+
}),
|
|
95
|
+
handler: async (args) => {
|
|
96
|
+
const { items, style, indent: rawIndent } = args;
|
|
97
|
+
const indent = Math.max(0, Math.floor(rawIndent));
|
|
98
|
+
const pad = " ".repeat(indent);
|
|
99
|
+
if (items.length === 0) return "";
|
|
100
|
+
switch (style) {
|
|
101
|
+
case "bullet": return items.map((item) => `${pad}• ${item}`).join("\n");
|
|
102
|
+
case "numbered": return items.map((item, i) => `${pad}${i + 1}. ${item}`).join("\n");
|
|
103
|
+
case "newline": return items.map((item) => `${pad}${item}`).join("\n");
|
|
104
|
+
case "inline_and":
|
|
105
|
+
case "inline_or": {
|
|
106
|
+
const conj = style === "inline_and" ? "and" : "or";
|
|
107
|
+
if (items.length === 1) return items[0];
|
|
108
|
+
if (items.length === 2) return `${items[0]} ${conj} ${items[1]}`;
|
|
109
|
+
const last = items[items.length - 1];
|
|
110
|
+
return `${items.slice(0, -1).join(", ")}, ${conj} ${last}`;
|
|
111
|
+
}
|
|
112
|
+
default: return `Error: Unknown style "${style}".`;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
//#endregion
|
|
117
|
+
exports.formatListTool = formatListTool;
|
|
118
|
+
exports.formatNumberTool = formatNumberTool;
|
|
119
|
+
|
|
120
|
+
//# sourceMappingURL=formatting.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatting.cjs","names":[],"sources":["../../../src/batteries/tools/formatting/index.ts"],"sourcesContent":["/**\n * Pre-constructed tools for locale-aware number, list, table, and text formatting.\n *\n * @module @nhtio/adk/batteries/tools/formatting\n *\n * @remarks\n * Pre-constructed bundled tools for the `formatting` category. Import individually, the whole\n * category, or import every tool via `@nhtio/adk/batteries`.\n */\n\nimport { Tool } from '@nhtio/adk/common'\nimport { isError } from '@nhtio/adk/guards'\nimport { validator } from '@nhtio/validation'\n\n/**\n * Format a number using locale-aware styles.\n *\n * @remarks\n * Supported styles: `decimal`, `currency`, `percent`, `compact` (e.g. `1.2K`), `scientific`\n * (e.g. `1.2e+3`), and `ordinal` (`1st`, `2nd`, `3rd`). Uses `Intl.NumberFormat` and\n * `Intl.PluralRules` from the JS standard library. Returns an error string for non-finite values\n * or invalid currency-without-currency-code.\n */\nexport const formatNumberTool = new Tool({\n name: 'format_number',\n description:\n 'Format a number using locale-aware styles: decimal, currency, percent, compact (1.2K), scientific (1.2e3), or ordinal (1st/2nd/3rd). Supports locale and precision options.',\n inputSchema: validator.object({\n value: validator.number().required().description('The number to format'),\n style: validator\n .string()\n .valid('decimal', 'currency', 'percent', 'compact', 'scientific', 'ordinal')\n .default('decimal')\n .description('Formatting style (default: decimal)'),\n currency: validator\n .string()\n .optional()\n .description(\n 'ISO 4217 currency code — required when style is \"currency\" (e.g. \"USD\", \"EUR\")'\n ),\n locale: validator.string().default('en-US').description('BCP 47 locale tag (default: \"en-US\")'),\n min_decimals: validator\n .number()\n .optional()\n .description('Minimum fraction digits (default: style-dependent)'),\n max_decimals: validator\n .number()\n .optional()\n .description('Maximum fraction digits (default: style-dependent)'),\n }),\n handler: async (args) => {\n const {\n value,\n style,\n locale,\n currency,\n min_decimals: minDec,\n max_decimals: maxDec,\n } = args as {\n value: number\n style: string\n locale: string\n currency?: string\n min_decimals?: number\n max_decimals?: number\n }\n\n if (!Number.isFinite(value)) return `Error: Value must be a finite number (got ${value}).`\n\n try {\n if (style === 'ordinal') {\n const pr = new Intl.PluralRules(locale, { type: 'ordinal' })\n const suffixes: Record<string, string> = { one: 'st', two: 'nd', few: 'rd', other: 'th' }\n const rule = pr.select(value)\n const suffix = suffixes[rule] ?? 'th'\n return `${new Intl.NumberFormat(locale).format(value)}${suffix}`\n }\n\n if (style === 'scientific') {\n const exp = value === 0 ? 0 : Math.floor(Math.log10(Math.abs(value)))\n const mantissa = value / Math.pow(10, exp)\n const mFormatted = new Intl.NumberFormat(locale, {\n minimumFractionDigits: minDec ?? 2,\n maximumFractionDigits: maxDec ?? 6,\n }).format(mantissa)\n return `${mFormatted}e${exp >= 0 ? '+' : ''}${exp}`\n }\n\n const opts: Intl.NumberFormatOptions = {}\n\n if (style === 'currency') {\n if (!currency) return 'Error: \"currency\" parameter is required when style is \"currency\".'\n opts.style = 'currency'\n opts.currency = currency.toUpperCase()\n } else if (style === 'percent') {\n opts.style = 'percent'\n opts.minimumFractionDigits = minDec ?? 1\n opts.maximumFractionDigits = maxDec ?? 2\n } else if (style === 'compact') {\n opts.notation = 'compact'\n opts.compactDisplay = 'short'\n } else {\n opts.style = 'decimal'\n }\n\n if (minDec !== undefined && style !== 'percent') opts.minimumFractionDigits = minDec\n if (maxDec !== undefined && style !== 'percent') opts.maximumFractionDigits = maxDec\n\n return new Intl.NumberFormat(locale, opts).format(value)\n } catch (err) {\n return `Error: ${isError(err) ? err.message : String(err)}`\n }\n },\n})\n\n/**\n * Format an array of items as a list.\n *\n * @remarks\n * Supported styles: `bullet` (`• item`), `numbered` (`1. item`), `inline_and`\n * (`a, b, and c`), `inline_or` (`a, b, or c`), `newline` (one per line).\n */\nexport const formatListTool = new Tool({\n name: 'format_list',\n description:\n 'Format an array of items as a list. Styles: bullet (• item), numbered (1. item), inline_and (\"a, b, and c\"), inline_or (\"a, b, or c\"), newline (one per line).',\n inputSchema: validator.object({\n items: validator\n .array()\n .items(validator.string())\n .required()\n .description('Array of items to format'),\n style: validator\n .string()\n .valid('bullet', 'numbered', 'inline_and', 'inline_or', 'newline')\n .default('bullet')\n .description('List format style (default: bullet)'),\n indent: validator.number().default(0).description('Spaces to indent each item (default: 0)'),\n }),\n handler: async (args) => {\n const {\n items,\n style,\n indent: rawIndent,\n } = args as {\n items: string[]\n style: string\n indent: number\n }\n const indent = Math.max(0, Math.floor(rawIndent))\n const pad = ' '.repeat(indent)\n\n if (items.length === 0) return ''\n\n switch (style) {\n case 'bullet':\n return items.map((item) => `${pad}• ${item}`).join('\\n')\n case 'numbered':\n return items.map((item, i) => `${pad}${i + 1}. ${item}`).join('\\n')\n case 'newline':\n return items.map((item) => `${pad}${item}`).join('\\n')\n case 'inline_and':\n case 'inline_or': {\n const conj = style === 'inline_and' ? 'and' : 'or'\n if (items.length === 1) return items[0]\n if (items.length === 2) return `${items[0]} ${conj} ${items[1]}`\n const last = items[items.length - 1]\n const rest = items.slice(0, -1)\n return `${rest.join(', ')}, ${conj} ${last}`\n }\n default:\n return `Error: Unknown style \"${style}\".`\n }\n },\n})\n"],"mappings":"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"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { o as isError } from "../../tool_registry-DqLOyGyG.mjs";
|
|
2
|
+
import "../../common-DeZaonK1.mjs";
|
|
3
|
+
import { t as Tool } from "../../tool-D2WB1EA1.mjs";
|
|
4
|
+
import "../../guards.mjs";
|
|
5
|
+
import { validator } from "@nhtio/validation";
|
|
6
|
+
//#region src/batteries/tools/formatting/index.ts
|
|
7
|
+
/**
|
|
8
|
+
* Pre-constructed tools for locale-aware number, list, table, and text formatting.
|
|
9
|
+
*
|
|
10
|
+
* @module @nhtio/adk/batteries/tools/formatting
|
|
11
|
+
*
|
|
12
|
+
* @remarks
|
|
13
|
+
* Pre-constructed bundled tools for the `formatting` category. Import individually, the whole
|
|
14
|
+
* category, or import every tool via `@nhtio/adk/batteries`.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Format a number using locale-aware styles.
|
|
18
|
+
*
|
|
19
|
+
* @remarks
|
|
20
|
+
* Supported styles: `decimal`, `currency`, `percent`, `compact` (e.g. `1.2K`), `scientific`
|
|
21
|
+
* (e.g. `1.2e+3`), and `ordinal` (`1st`, `2nd`, `3rd`). Uses `Intl.NumberFormat` and
|
|
22
|
+
* `Intl.PluralRules` from the JS standard library. Returns an error string for non-finite values
|
|
23
|
+
* or invalid currency-without-currency-code.
|
|
24
|
+
*/
|
|
25
|
+
var formatNumberTool = new Tool({
|
|
26
|
+
name: "format_number",
|
|
27
|
+
description: "Format a number using locale-aware styles: decimal, currency, percent, compact (1.2K), scientific (1.2e3), or ordinal (1st/2nd/3rd). Supports locale and precision options.",
|
|
28
|
+
inputSchema: validator.object({
|
|
29
|
+
value: validator.number().required().description("The number to format"),
|
|
30
|
+
style: validator.string().valid("decimal", "currency", "percent", "compact", "scientific", "ordinal").default("decimal").description("Formatting style (default: decimal)"),
|
|
31
|
+
currency: validator.string().optional().description("ISO 4217 currency code — required when style is \"currency\" (e.g. \"USD\", \"EUR\")"),
|
|
32
|
+
locale: validator.string().default("en-US").description("BCP 47 locale tag (default: \"en-US\")"),
|
|
33
|
+
min_decimals: validator.number().optional().description("Minimum fraction digits (default: style-dependent)"),
|
|
34
|
+
max_decimals: validator.number().optional().description("Maximum fraction digits (default: style-dependent)")
|
|
35
|
+
}),
|
|
36
|
+
handler: async (args) => {
|
|
37
|
+
const { value, style, locale, currency, min_decimals: minDec, max_decimals: maxDec } = args;
|
|
38
|
+
if (!Number.isFinite(value)) return `Error: Value must be a finite number (got ${value}).`;
|
|
39
|
+
try {
|
|
40
|
+
if (style === "ordinal") {
|
|
41
|
+
const suffix = {
|
|
42
|
+
one: "st",
|
|
43
|
+
two: "nd",
|
|
44
|
+
few: "rd",
|
|
45
|
+
other: "th"
|
|
46
|
+
}[new Intl.PluralRules(locale, { type: "ordinal" }).select(value)] ?? "th";
|
|
47
|
+
return `${new Intl.NumberFormat(locale).format(value)}${suffix}`;
|
|
48
|
+
}
|
|
49
|
+
if (style === "scientific") {
|
|
50
|
+
const exp = value === 0 ? 0 : Math.floor(Math.log10(Math.abs(value)));
|
|
51
|
+
const mantissa = value / Math.pow(10, exp);
|
|
52
|
+
return `${new Intl.NumberFormat(locale, {
|
|
53
|
+
minimumFractionDigits: minDec ?? 2,
|
|
54
|
+
maximumFractionDigits: maxDec ?? 6
|
|
55
|
+
}).format(mantissa)}e${exp >= 0 ? "+" : ""}${exp}`;
|
|
56
|
+
}
|
|
57
|
+
const opts = {};
|
|
58
|
+
if (style === "currency") {
|
|
59
|
+
if (!currency) return "Error: \"currency\" parameter is required when style is \"currency\".";
|
|
60
|
+
opts.style = "currency";
|
|
61
|
+
opts.currency = currency.toUpperCase();
|
|
62
|
+
} else if (style === "percent") {
|
|
63
|
+
opts.style = "percent";
|
|
64
|
+
opts.minimumFractionDigits = minDec ?? 1;
|
|
65
|
+
opts.maximumFractionDigits = maxDec ?? 2;
|
|
66
|
+
} else if (style === "compact") {
|
|
67
|
+
opts.notation = "compact";
|
|
68
|
+
opts.compactDisplay = "short";
|
|
69
|
+
} else opts.style = "decimal";
|
|
70
|
+
if (minDec !== void 0 && style !== "percent") opts.minimumFractionDigits = minDec;
|
|
71
|
+
if (maxDec !== void 0 && style !== "percent") opts.maximumFractionDigits = maxDec;
|
|
72
|
+
return new Intl.NumberFormat(locale, opts).format(value);
|
|
73
|
+
} catch (err) {
|
|
74
|
+
return `Error: ${isError(err) ? err.message : String(err)}`;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
/**
|
|
79
|
+
* Format an array of items as a list.
|
|
80
|
+
*
|
|
81
|
+
* @remarks
|
|
82
|
+
* Supported styles: `bullet` (`• item`), `numbered` (`1. item`), `inline_and`
|
|
83
|
+
* (`a, b, and c`), `inline_or` (`a, b, or c`), `newline` (one per line).
|
|
84
|
+
*/
|
|
85
|
+
var formatListTool = new Tool({
|
|
86
|
+
name: "format_list",
|
|
87
|
+
description: "Format an array of items as a list. Styles: bullet (• item), numbered (1. item), inline_and (\"a, b, and c\"), inline_or (\"a, b, or c\"), newline (one per line).",
|
|
88
|
+
inputSchema: validator.object({
|
|
89
|
+
items: validator.array().items(validator.string()).required().description("Array of items to format"),
|
|
90
|
+
style: validator.string().valid("bullet", "numbered", "inline_and", "inline_or", "newline").default("bullet").description("List format style (default: bullet)"),
|
|
91
|
+
indent: validator.number().default(0).description("Spaces to indent each item (default: 0)")
|
|
92
|
+
}),
|
|
93
|
+
handler: async (args) => {
|
|
94
|
+
const { items, style, indent: rawIndent } = args;
|
|
95
|
+
const indent = Math.max(0, Math.floor(rawIndent));
|
|
96
|
+
const pad = " ".repeat(indent);
|
|
97
|
+
if (items.length === 0) return "";
|
|
98
|
+
switch (style) {
|
|
99
|
+
case "bullet": return items.map((item) => `${pad}• ${item}`).join("\n");
|
|
100
|
+
case "numbered": return items.map((item, i) => `${pad}${i + 1}. ${item}`).join("\n");
|
|
101
|
+
case "newline": return items.map((item) => `${pad}${item}`).join("\n");
|
|
102
|
+
case "inline_and":
|
|
103
|
+
case "inline_or": {
|
|
104
|
+
const conj = style === "inline_and" ? "and" : "or";
|
|
105
|
+
if (items.length === 1) return items[0];
|
|
106
|
+
if (items.length === 2) return `${items[0]} ${conj} ${items[1]}`;
|
|
107
|
+
const last = items[items.length - 1];
|
|
108
|
+
return `${items.slice(0, -1).join(", ")}, ${conj} ${last}`;
|
|
109
|
+
}
|
|
110
|
+
default: return `Error: Unknown style "${style}".`;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
//#endregion
|
|
115
|
+
export { formatListTool, formatNumberTool };
|
|
116
|
+
|
|
117
|
+
//# sourceMappingURL=formatting.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatting.mjs","names":[],"sources":["../../../src/batteries/tools/formatting/index.ts"],"sourcesContent":["/**\n * Pre-constructed tools for locale-aware number, list, table, and text formatting.\n *\n * @module @nhtio/adk/batteries/tools/formatting\n *\n * @remarks\n * Pre-constructed bundled tools for the `formatting` category. Import individually, the whole\n * category, or import every tool via `@nhtio/adk/batteries`.\n */\n\nimport { Tool } from '@nhtio/adk/common'\nimport { isError } from '@nhtio/adk/guards'\nimport { validator } from '@nhtio/validation'\n\n/**\n * Format a number using locale-aware styles.\n *\n * @remarks\n * Supported styles: `decimal`, `currency`, `percent`, `compact` (e.g. `1.2K`), `scientific`\n * (e.g. `1.2e+3`), and `ordinal` (`1st`, `2nd`, `3rd`). Uses `Intl.NumberFormat` and\n * `Intl.PluralRules` from the JS standard library. Returns an error string for non-finite values\n * or invalid currency-without-currency-code.\n */\nexport const formatNumberTool = new Tool({\n name: 'format_number',\n description:\n 'Format a number using locale-aware styles: decimal, currency, percent, compact (1.2K), scientific (1.2e3), or ordinal (1st/2nd/3rd). Supports locale and precision options.',\n inputSchema: validator.object({\n value: validator.number().required().description('The number to format'),\n style: validator\n .string()\n .valid('decimal', 'currency', 'percent', 'compact', 'scientific', 'ordinal')\n .default('decimal')\n .description('Formatting style (default: decimal)'),\n currency: validator\n .string()\n .optional()\n .description(\n 'ISO 4217 currency code — required when style is \"currency\" (e.g. \"USD\", \"EUR\")'\n ),\n locale: validator.string().default('en-US').description('BCP 47 locale tag (default: \"en-US\")'),\n min_decimals: validator\n .number()\n .optional()\n .description('Minimum fraction digits (default: style-dependent)'),\n max_decimals: validator\n .number()\n .optional()\n .description('Maximum fraction digits (default: style-dependent)'),\n }),\n handler: async (args) => {\n const {\n value,\n style,\n locale,\n currency,\n min_decimals: minDec,\n max_decimals: maxDec,\n } = args as {\n value: number\n style: string\n locale: string\n currency?: string\n min_decimals?: number\n max_decimals?: number\n }\n\n if (!Number.isFinite(value)) return `Error: Value must be a finite number (got ${value}).`\n\n try {\n if (style === 'ordinal') {\n const pr = new Intl.PluralRules(locale, { type: 'ordinal' })\n const suffixes: Record<string, string> = { one: 'st', two: 'nd', few: 'rd', other: 'th' }\n const rule = pr.select(value)\n const suffix = suffixes[rule] ?? 'th'\n return `${new Intl.NumberFormat(locale).format(value)}${suffix}`\n }\n\n if (style === 'scientific') {\n const exp = value === 0 ? 0 : Math.floor(Math.log10(Math.abs(value)))\n const mantissa = value / Math.pow(10, exp)\n const mFormatted = new Intl.NumberFormat(locale, {\n minimumFractionDigits: minDec ?? 2,\n maximumFractionDigits: maxDec ?? 6,\n }).format(mantissa)\n return `${mFormatted}e${exp >= 0 ? '+' : ''}${exp}`\n }\n\n const opts: Intl.NumberFormatOptions = {}\n\n if (style === 'currency') {\n if (!currency) return 'Error: \"currency\" parameter is required when style is \"currency\".'\n opts.style = 'currency'\n opts.currency = currency.toUpperCase()\n } else if (style === 'percent') {\n opts.style = 'percent'\n opts.minimumFractionDigits = minDec ?? 1\n opts.maximumFractionDigits = maxDec ?? 2\n } else if (style === 'compact') {\n opts.notation = 'compact'\n opts.compactDisplay = 'short'\n } else {\n opts.style = 'decimal'\n }\n\n if (minDec !== undefined && style !== 'percent') opts.minimumFractionDigits = minDec\n if (maxDec !== undefined && style !== 'percent') opts.maximumFractionDigits = maxDec\n\n return new Intl.NumberFormat(locale, opts).format(value)\n } catch (err) {\n return `Error: ${isError(err) ? err.message : String(err)}`\n }\n },\n})\n\n/**\n * Format an array of items as a list.\n *\n * @remarks\n * Supported styles: `bullet` (`• item`), `numbered` (`1. item`), `inline_and`\n * (`a, b, and c`), `inline_or` (`a, b, or c`), `newline` (one per line).\n */\nexport const formatListTool = new Tool({\n name: 'format_list',\n description:\n 'Format an array of items as a list. Styles: bullet (• item), numbered (1. item), inline_and (\"a, b, and c\"), inline_or (\"a, b, or c\"), newline (one per line).',\n inputSchema: validator.object({\n items: validator\n .array()\n .items(validator.string())\n .required()\n .description('Array of items to format'),\n style: validator\n .string()\n .valid('bullet', 'numbered', 'inline_and', 'inline_or', 'newline')\n .default('bullet')\n .description('List format style (default: bullet)'),\n indent: validator.number().default(0).description('Spaces to indent each item (default: 0)'),\n }),\n handler: async (args) => {\n const {\n items,\n style,\n indent: rawIndent,\n } = args as {\n items: string[]\n style: string\n indent: number\n }\n const indent = Math.max(0, Math.floor(rawIndent))\n const pad = ' '.repeat(indent)\n\n if (items.length === 0) return ''\n\n switch (style) {\n case 'bullet':\n return items.map((item) => `${pad}• ${item}`).join('\\n')\n case 'numbered':\n return items.map((item, i) => `${pad}${i + 1}. ${item}`).join('\\n')\n case 'newline':\n return items.map((item) => `${pad}${item}`).join('\\n')\n case 'inline_and':\n case 'inline_or': {\n const conj = style === 'inline_and' ? 'and' : 'or'\n if (items.length === 1) return items[0]\n if (items.length === 2) return `${items[0]} ${conj} ${items[1]}`\n const last = items[items.length - 1]\n const rest = items.slice(0, -1)\n return `${rest.join(', ')}, ${conj} ${last}`\n }\n default:\n return `Error: Unknown style \"${style}\".`\n }\n },\n})\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAuBA,IAAa,mBAAmB,IAAI,KAAK;CACvC,MAAM;CACN,aACE;CACF,aAAa,UAAU,OAAO;EAC5B,OAAO,UAAU,OAAO,EAAE,SAAS,EAAE,YAAY,sBAAsB;EACvE,OAAO,UACJ,OAAO,EACP,MAAM,WAAW,YAAY,WAAW,WAAW,cAAc,SAAS,EAC1E,QAAQ,SAAS,EACjB,YAAY,qCAAqC;EACpD,UAAU,UACP,OAAO,EACP,SAAS,EACT,YACC,sFACF;EACF,QAAQ,UAAU,OAAO,EAAE,QAAQ,OAAO,EAAE,YAAY,wCAAsC;EAC9F,cAAc,UACX,OAAO,EACP,SAAS,EACT,YAAY,oDAAoD;EACnE,cAAc,UACX,OAAO,EACP,SAAS,EACT,YAAY,oDAAoD;CACrE,CAAC;CACD,SAAS,OAAO,SAAS;EACvB,MAAM,EACJ,OACA,OACA,QACA,UACA,cAAc,QACd,cAAc,WACZ;EASJ,IAAI,CAAC,OAAO,SAAS,KAAK,GAAG,OAAO,6CAA6C,MAAM;EAEvF,IAAI;GACF,IAAI,UAAU,WAAW;IAIvB,MAAM,SAAS;KAF4B,KAAK;KAAM,KAAK;KAAM,KAAK;KAAM,OAAO;IAEpE,EADF,IAFE,KAAK,YAAY,QAAQ,EAAE,MAAM,UAAU,CAE7C,EAAG,OAAO,KACC,MAAS;IACjC,OAAO,GAAG,IAAI,KAAK,aAAa,MAAM,EAAE,OAAO,KAAK,IAAI;GAC1D;GAEA,IAAI,UAAU,cAAc;IAC1B,MAAM,MAAM,UAAU,IAAI,IAAI,KAAK,MAAM,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,CAAC;IACpE,MAAM,WAAW,QAAQ,KAAK,IAAI,IAAI,GAAG;IAKzC,OAAO,GAJY,IAAI,KAAK,aAAa,QAAQ;KAC/C,uBAAuB,UAAU;KACjC,uBAAuB,UAAU;IACnC,CAAC,EAAE,OAAO,QACA,EAAW,GAAG,OAAO,IAAI,MAAM,KAAK;GAChD;GAEA,MAAM,OAAiC,CAAC;GAExC,IAAI,UAAU,YAAY;IACxB,IAAI,CAAC,UAAU,OAAO;IACtB,KAAK,QAAQ;IACb,KAAK,WAAW,SAAS,YAAY;GACvC,OAAO,IAAI,UAAU,WAAW;IAC9B,KAAK,QAAQ;IACb,KAAK,wBAAwB,UAAU;IACvC,KAAK,wBAAwB,UAAU;GACzC,OAAO,IAAI,UAAU,WAAW;IAC9B,KAAK,WAAW;IAChB,KAAK,iBAAiB;GACxB,OACE,KAAK,QAAQ;GAGf,IAAI,WAAW,KAAA,KAAa,UAAU,WAAW,KAAK,wBAAwB;GAC9E,IAAI,WAAW,KAAA,KAAa,UAAU,WAAW,KAAK,wBAAwB;GAE9E,OAAO,IAAI,KAAK,aAAa,QAAQ,IAAI,EAAE,OAAO,KAAK;EACzD,SAAS,KAAK;GACZ,OAAO,UAAU,QAAQ,GAAG,IAAI,IAAI,UAAU,OAAO,GAAG;EAC1D;CACF;AACF,CAAC;;;;;;;;AASD,IAAa,iBAAiB,IAAI,KAAK;CACrC,MAAM;CACN,aACE;CACF,aAAa,UAAU,OAAO;EAC5B,OAAO,UACJ,MAAM,EACN,MAAM,UAAU,OAAO,CAAC,EACxB,SAAS,EACT,YAAY,0BAA0B;EACzC,OAAO,UACJ,OAAO,EACP,MAAM,UAAU,YAAY,cAAc,aAAa,SAAS,EAChE,QAAQ,QAAQ,EAChB,YAAY,qCAAqC;EACpD,QAAQ,UAAU,OAAO,EAAE,QAAQ,CAAC,EAAE,YAAY,yCAAyC;CAC7F,CAAC;CACD,SAAS,OAAO,SAAS;EACvB,MAAM,EACJ,OACA,OACA,QAAQ,cACN;EAKJ,MAAM,SAAS,KAAK,IAAI,GAAG,KAAK,MAAM,SAAS,CAAC;EAChD,MAAM,MAAM,IAAI,OAAO,MAAM;EAE7B,IAAI,MAAM,WAAW,GAAG,OAAO;EAE/B,QAAQ,OAAR;GACE,KAAK,UACH,OAAO,MAAM,KAAK,SAAS,GAAG,IAAI,IAAI,MAAM,EAAE,KAAK,IAAI;GACzD,KAAK,YACH,OAAO,MAAM,KAAK,MAAM,MAAM,GAAG,MAAM,IAAI,EAAE,IAAI,MAAM,EAAE,KAAK,IAAI;GACpE,KAAK,WACH,OAAO,MAAM,KAAK,SAAS,GAAG,MAAM,MAAM,EAAE,KAAK,IAAI;GACvD,KAAK;GACL,KAAK,aAAa;IAChB,MAAM,OAAO,UAAU,eAAe,QAAQ;IAC9C,IAAI,MAAM,WAAW,GAAG,OAAO,MAAM;IACrC,IAAI,MAAM,WAAW,GAAG,OAAO,GAAG,MAAM,GAAG,GAAG,KAAK,GAAG,MAAM;IAC5D,MAAM,OAAO,MAAM,MAAM,SAAS;IAElC,OAAO,GADM,MAAM,MAAM,GAAG,EAClB,EAAK,KAAK,IAAI,EAAE,IAAI,KAAK,GAAG;GACxC;GACA,SACE,OAAO,yBAAyB,MAAM;EAC1C;CACF;AACF,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pre-constructed tools for basic geographic distance and coordinate calculations.
|
|
3
|
+
*
|
|
4
|
+
* @module @nhtio/adk/batteries/tools/geo_basics
|
|
5
|
+
*
|
|
6
|
+
* @remarks
|
|
7
|
+
* Pre-constructed bundled tools for the `geo_basics` category. Import individually, the whole
|
|
8
|
+
* category, or import every tool via `@nhtio/adk/batteries`.
|
|
9
|
+
*/
|
|
10
|
+
import { Tool } from "../../../common";
|
|
11
|
+
/**
|
|
12
|
+
* Great-circle (haversine) distance between two geographic coordinates.
|
|
13
|
+
*
|
|
14
|
+
* @remarks
|
|
15
|
+
* Uses the Earth's mean radius (6371.0088 km). Returns both kilometres and miles.
|
|
16
|
+
*/
|
|
17
|
+
export declare const geoDistanceTool: Tool<import("../../../common").SpooledArtifact>;
|
|
18
|
+
/**
|
|
19
|
+
* Check whether a point lies within a radius of a centre coordinate.
|
|
20
|
+
*
|
|
21
|
+
* @remarks
|
|
22
|
+
* Uses the haversine distance internally; returns the radius unit chosen by the caller
|
|
23
|
+
* (km or miles) in the result string.
|
|
24
|
+
*/
|
|
25
|
+
export declare const geoWithinRadiusTool: Tool<import("../../../common").SpooledArtifact>;
|
|
26
|
+
/**
|
|
27
|
+
* Check whether a point falls inside an axis-aligned bounding box.
|
|
28
|
+
*
|
|
29
|
+
* @remarks
|
|
30
|
+
* The bounding box is defined by its SW and NE corners. Boxes that wrap the antimeridian
|
|
31
|
+
* (i.e. SW longitude greater than NE longitude) are handled correctly.
|
|
32
|
+
*/
|
|
33
|
+
export declare const geoBboxContainsTool: Tool<import("../../../common").SpooledArtifact>;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
require("../../chunk-KmRHZBOW.js");
|
|
3
|
+
require("../../common-Od8edUXU.js");
|
|
4
|
+
const require_tool = require("../../tool-COSeH8I6.js");
|
|
5
|
+
let _nhtio_validation = require("@nhtio/validation");
|
|
6
|
+
//#region src/batteries/tools/geo_basics/index.ts
|
|
7
|
+
/**
|
|
8
|
+
* Pre-constructed tools for basic geographic distance and coordinate calculations.
|
|
9
|
+
*
|
|
10
|
+
* @module @nhtio/adk/batteries/tools/geo_basics
|
|
11
|
+
*
|
|
12
|
+
* @remarks
|
|
13
|
+
* Pre-constructed bundled tools for the `geo_basics` category. Import individually, the whole
|
|
14
|
+
* category, or import every tool via `@nhtio/adk/batteries`.
|
|
15
|
+
*/
|
|
16
|
+
var EARTH_RADIUS_KM = 6371.0088;
|
|
17
|
+
function toRad(deg) {
|
|
18
|
+
return deg * Math.PI / 180;
|
|
19
|
+
}
|
|
20
|
+
function haversineKm(lat1, lon1, lat2, lon2) {
|
|
21
|
+
const dLat = toRad(lat2 - lat1);
|
|
22
|
+
const dLon = toRad(lon2 - lon1);
|
|
23
|
+
const a = Math.sin(dLat / 2) ** 2 + Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLon / 2) ** 2;
|
|
24
|
+
return 2 * EARTH_RADIUS_KM * Math.asin(Math.sqrt(a));
|
|
25
|
+
}
|
|
26
|
+
function validateLatLon(lat, lon, label) {
|
|
27
|
+
if (typeof lat !== "number" || !Number.isFinite(lat) || lat < -90 || lat > 90) return `Error: ${label} latitude must be a number between -90 and 90.`;
|
|
28
|
+
if (typeof lon !== "number" || !Number.isFinite(lon) || lon < -180 || lon > 180) return `Error: ${label} longitude must be a number between -180 and 180.`;
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Great-circle (haversine) distance between two geographic coordinates.
|
|
33
|
+
*
|
|
34
|
+
* @remarks
|
|
35
|
+
* Uses the Earth's mean radius (6371.0088 km). Returns both kilometres and miles.
|
|
36
|
+
*/
|
|
37
|
+
var geoDistanceTool = new require_tool.Tool({
|
|
38
|
+
name: "geo_distance",
|
|
39
|
+
description: "Calculate the great-circle (haversine) distance between two geographic coordinates. Returns distance in km and miles.",
|
|
40
|
+
inputSchema: _nhtio_validation.validator.object({
|
|
41
|
+
lat1: _nhtio_validation.validator.number().required().description("Latitude of point A (decimal degrees, -90 to 90)"),
|
|
42
|
+
lon1: _nhtio_validation.validator.number().required().description("Longitude of point A (decimal degrees, -180 to 180)"),
|
|
43
|
+
lat2: _nhtio_validation.validator.number().required().description("Latitude of point B (decimal degrees, -90 to 90)"),
|
|
44
|
+
lon2: _nhtio_validation.validator.number().required().description("Longitude of point B (decimal degrees, -180 to 180)")
|
|
45
|
+
}),
|
|
46
|
+
handler: async (args) => {
|
|
47
|
+
const { lat1, lon1, lat2, lon2 } = args;
|
|
48
|
+
const errA = validateLatLon(lat1, lon1, "point A");
|
|
49
|
+
if (errA) return errA;
|
|
50
|
+
const errB = validateLatLon(lat2, lon2, "point B");
|
|
51
|
+
if (errB) return errB;
|
|
52
|
+
const km = haversineKm(lat1, lon1, lat2, lon2);
|
|
53
|
+
const miles = km * .621371;
|
|
54
|
+
return `Distance: ${km.toFixed(4)} km / ${miles.toFixed(4)} miles`;
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
/**
|
|
58
|
+
* Check whether a point lies within a radius of a centre coordinate.
|
|
59
|
+
*
|
|
60
|
+
* @remarks
|
|
61
|
+
* Uses the haversine distance internally; returns the radius unit chosen by the caller
|
|
62
|
+
* (km or miles) in the result string.
|
|
63
|
+
*/
|
|
64
|
+
var geoWithinRadiusTool = new require_tool.Tool({
|
|
65
|
+
name: "geo_within_radius",
|
|
66
|
+
description: "Check whether a point is within a given radius (km or miles) of a center coordinate.",
|
|
67
|
+
inputSchema: _nhtio_validation.validator.object({
|
|
68
|
+
center_lat: _nhtio_validation.validator.number().required().description("Center latitude"),
|
|
69
|
+
center_lon: _nhtio_validation.validator.number().required().description("Center longitude"),
|
|
70
|
+
point_lat: _nhtio_validation.validator.number().required().description("Point latitude to test"),
|
|
71
|
+
point_lon: _nhtio_validation.validator.number().required().description("Point longitude to test"),
|
|
72
|
+
radius: _nhtio_validation.validator.number().required().description("Radius value (must be positive)"),
|
|
73
|
+
unit: _nhtio_validation.validator.string().valid("km", "miles").default("km").description("Unit for the radius (default: km)")
|
|
74
|
+
}),
|
|
75
|
+
handler: async (args) => {
|
|
76
|
+
const { center_lat: centerLat, center_lon: centerLon, point_lat: pointLat, point_lon: pointLon, radius, unit } = args;
|
|
77
|
+
const errC = validateLatLon(centerLat, centerLon, "center");
|
|
78
|
+
if (errC) return errC;
|
|
79
|
+
const errP = validateLatLon(pointLat, pointLon, "point");
|
|
80
|
+
if (errP) return errP;
|
|
81
|
+
if (!Number.isFinite(radius) || radius <= 0) return "Error: radius must be a positive number.";
|
|
82
|
+
const km = haversineKm(centerLat, centerLon, pointLat, pointLon);
|
|
83
|
+
const distInUnit = unit === "miles" ? km * .621371 : km;
|
|
84
|
+
return `${distInUnit <= radius ? "Yes" : "No"} — distance is ${distInUnit.toFixed(4)} ${unit} (radius: ${radius} ${unit})`;
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
/**
|
|
88
|
+
* Check whether a point falls inside an axis-aligned bounding box.
|
|
89
|
+
*
|
|
90
|
+
* @remarks
|
|
91
|
+
* The bounding box is defined by its SW and NE corners. Boxes that wrap the antimeridian
|
|
92
|
+
* (i.e. SW longitude greater than NE longitude) are handled correctly.
|
|
93
|
+
*/
|
|
94
|
+
var geoBboxContainsTool = new require_tool.Tool({
|
|
95
|
+
name: "geo_bbox_contains",
|
|
96
|
+
description: "Check whether a point falls inside an axis-aligned bounding box defined by its SW and NE corners.",
|
|
97
|
+
inputSchema: _nhtio_validation.validator.object({
|
|
98
|
+
sw_lat: _nhtio_validation.validator.number().required().description("South-west corner latitude"),
|
|
99
|
+
sw_lon: _nhtio_validation.validator.number().required().description("South-west corner longitude"),
|
|
100
|
+
ne_lat: _nhtio_validation.validator.number().required().description("North-east corner latitude"),
|
|
101
|
+
ne_lon: _nhtio_validation.validator.number().required().description("North-east corner longitude"),
|
|
102
|
+
point_lat: _nhtio_validation.validator.number().required().description("Point latitude to test"),
|
|
103
|
+
point_lon: _nhtio_validation.validator.number().required().description("Point longitude to test")
|
|
104
|
+
}),
|
|
105
|
+
handler: async (args) => {
|
|
106
|
+
const { sw_lat: swLat, sw_lon: swLon, ne_lat: neLat, ne_lon: neLon, point_lat: pointLat, point_lon: pointLon } = args;
|
|
107
|
+
for (const [lat, lon, label] of [
|
|
108
|
+
[
|
|
109
|
+
swLat,
|
|
110
|
+
swLon,
|
|
111
|
+
"SW"
|
|
112
|
+
],
|
|
113
|
+
[
|
|
114
|
+
neLat,
|
|
115
|
+
neLon,
|
|
116
|
+
"NE"
|
|
117
|
+
],
|
|
118
|
+
[
|
|
119
|
+
pointLat,
|
|
120
|
+
pointLon,
|
|
121
|
+
"point"
|
|
122
|
+
]
|
|
123
|
+
]) {
|
|
124
|
+
const err = validateLatLon(lat, lon, label);
|
|
125
|
+
if (err) return err;
|
|
126
|
+
}
|
|
127
|
+
if (swLat > neLat) return "Error: SW latitude must be ≤ NE latitude.";
|
|
128
|
+
return pointLat >= swLat && pointLat <= neLat && (swLon <= neLon ? pointLon >= swLon && pointLon <= neLon : pointLon >= swLon || pointLon <= neLon) ? `Yes — point (${pointLat}, ${pointLon}) is inside the bounding box.` : `No — point (${pointLat}, ${pointLon}) is outside the bounding box.`;
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
//#endregion
|
|
132
|
+
exports.geoBboxContainsTool = geoBboxContainsTool;
|
|
133
|
+
exports.geoDistanceTool = geoDistanceTool;
|
|
134
|
+
exports.geoWithinRadiusTool = geoWithinRadiusTool;
|
|
135
|
+
|
|
136
|
+
//# sourceMappingURL=geo_basics.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geo_basics.cjs","names":[],"sources":["../../../src/batteries/tools/geo_basics/index.ts"],"sourcesContent":["/**\n * Pre-constructed tools for basic geographic distance and coordinate calculations.\n *\n * @module @nhtio/adk/batteries/tools/geo_basics\n *\n * @remarks\n * Pre-constructed bundled tools for the `geo_basics` category. Import individually, the whole\n * category, or import every tool via `@nhtio/adk/batteries`.\n */\n\nimport { Tool } from '@nhtio/adk/common'\nimport { validator } from '@nhtio/validation'\n\nconst EARTH_RADIUS_KM = 6371.0088\n\nfunction toRad(deg: number): number {\n return (deg * Math.PI) / 180\n}\n\nfunction haversineKm(lat1: number, lon1: number, lat2: number, lon2: number): number {\n const dLat = toRad(lat2 - lat1)\n const dLon = toRad(lon2 - lon1)\n const a =\n Math.sin(dLat / 2) ** 2 +\n Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLon / 2) ** 2\n return 2 * EARTH_RADIUS_KM * Math.asin(Math.sqrt(a))\n}\n\nfunction validateLatLon(lat: unknown, lon: unknown, label: string): string | null {\n if (typeof lat !== 'number' || !Number.isFinite(lat) || lat < -90 || lat > 90)\n return `Error: ${label} latitude must be a number between -90 and 90.`\n if (typeof lon !== 'number' || !Number.isFinite(lon) || lon < -180 || lon > 180)\n return `Error: ${label} longitude must be a number between -180 and 180.`\n return null\n}\n\n/**\n * Great-circle (haversine) distance between two geographic coordinates.\n *\n * @remarks\n * Uses the Earth's mean radius (6371.0088 km). Returns both kilometres and miles.\n */\nexport const geoDistanceTool = new Tool({\n name: 'geo_distance',\n description:\n 'Calculate the great-circle (haversine) distance between two geographic coordinates. Returns distance in km and miles.',\n inputSchema: validator.object({\n lat1: validator\n .number()\n .required()\n .description('Latitude of point A (decimal degrees, -90 to 90)'),\n lon1: validator\n .number()\n .required()\n .description('Longitude of point A (decimal degrees, -180 to 180)'),\n lat2: validator\n .number()\n .required()\n .description('Latitude of point B (decimal degrees, -90 to 90)'),\n lon2: validator\n .number()\n .required()\n .description('Longitude of point B (decimal degrees, -180 to 180)'),\n }),\n handler: async (args) => {\n const { lat1, lon1, lat2, lon2 } = args as {\n lat1: number\n lon1: number\n lat2: number\n lon2: number\n }\n\n const errA = validateLatLon(lat1, lon1, 'point A')\n if (errA) return errA\n const errB = validateLatLon(lat2, lon2, 'point B')\n if (errB) return errB\n\n const km = haversineKm(lat1, lon1, lat2, lon2)\n const miles = km * 0.621371\n\n return `Distance: ${km.toFixed(4)} km / ${miles.toFixed(4)} miles`\n },\n})\n\n/**\n * Check whether a point lies within a radius of a centre coordinate.\n *\n * @remarks\n * Uses the haversine distance internally; returns the radius unit chosen by the caller\n * (km or miles) in the result string.\n */\nexport const geoWithinRadiusTool = new Tool({\n name: 'geo_within_radius',\n description:\n 'Check whether a point is within a given radius (km or miles) of a center coordinate.',\n inputSchema: validator.object({\n center_lat: validator.number().required().description('Center latitude'),\n center_lon: validator.number().required().description('Center longitude'),\n point_lat: validator.number().required().description('Point latitude to test'),\n point_lon: validator.number().required().description('Point longitude to test'),\n radius: validator.number().required().description('Radius value (must be positive)'),\n unit: validator\n .string()\n .valid('km', 'miles')\n .default('km')\n .description('Unit for the radius (default: km)'),\n }),\n handler: async (args) => {\n const {\n center_lat: centerLat,\n center_lon: centerLon,\n point_lat: pointLat,\n point_lon: pointLon,\n radius,\n unit,\n } = args as {\n center_lat: number\n center_lon: number\n point_lat: number\n point_lon: number\n radius: number\n unit: string\n }\n\n const errC = validateLatLon(centerLat, centerLon, 'center')\n if (errC) return errC\n const errP = validateLatLon(pointLat, pointLon, 'point')\n if (errP) return errP\n if (!Number.isFinite(radius) || radius <= 0) return 'Error: radius must be a positive number.'\n\n const km = haversineKm(centerLat, centerLon, pointLat, pointLon)\n const distInUnit = unit === 'miles' ? km * 0.621371 : km\n const within = distInUnit <= radius\n\n return `${within ? 'Yes' : 'No'} — distance is ${distInUnit.toFixed(4)} ${unit} (radius: ${radius} ${unit})`\n },\n})\n\n/**\n * Check whether a point falls inside an axis-aligned bounding box.\n *\n * @remarks\n * The bounding box is defined by its SW and NE corners. Boxes that wrap the antimeridian\n * (i.e. SW longitude greater than NE longitude) are handled correctly.\n */\nexport const geoBboxContainsTool = new Tool({\n name: 'geo_bbox_contains',\n description:\n 'Check whether a point falls inside an axis-aligned bounding box defined by its SW and NE corners.',\n inputSchema: validator.object({\n sw_lat: validator.number().required().description('South-west corner latitude'),\n sw_lon: validator.number().required().description('South-west corner longitude'),\n ne_lat: validator.number().required().description('North-east corner latitude'),\n ne_lon: validator.number().required().description('North-east corner longitude'),\n point_lat: validator.number().required().description('Point latitude to test'),\n point_lon: validator.number().required().description('Point longitude to test'),\n }),\n handler: async (args) => {\n const {\n sw_lat: swLat,\n sw_lon: swLon,\n ne_lat: neLat,\n ne_lon: neLon,\n point_lat: pointLat,\n point_lon: pointLon,\n } = args as {\n sw_lat: number\n sw_lon: number\n ne_lat: number\n ne_lon: number\n point_lat: number\n point_lon: number\n }\n\n for (const [lat, lon, label] of [\n [swLat, swLon, 'SW'],\n [neLat, neLon, 'NE'],\n [pointLat, pointLon, 'point'],\n ] as [number, number, string][]) {\n const err = validateLatLon(lat, lon, label)\n if (err) return err\n }\n\n if (swLat > neLat) return 'Error: SW latitude must be ≤ NE latitude.'\n\n const latIn = pointLat >= swLat && pointLat <= neLat\n\n // Handle bounding boxes that wrap the antimeridian\n const lonIn =\n swLon <= neLon\n ? pointLon >= swLon && pointLon <= neLon\n : pointLon >= swLon || pointLon <= neLon\n\n const inside = latIn && lonIn\n return inside\n ? `Yes — point (${pointLat}, ${pointLon}) is inside the bounding box.`\n : `No — point (${pointLat}, ${pointLon}) is outside the bounding box.`\n },\n})\n"],"mappings":"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"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import "../../common-DeZaonK1.mjs";
|
|
2
|
+
import { t as Tool } from "../../tool-D2WB1EA1.mjs";
|
|
3
|
+
import { validator } from "@nhtio/validation";
|
|
4
|
+
//#region src/batteries/tools/geo_basics/index.ts
|
|
5
|
+
/**
|
|
6
|
+
* Pre-constructed tools for basic geographic distance and coordinate calculations.
|
|
7
|
+
*
|
|
8
|
+
* @module @nhtio/adk/batteries/tools/geo_basics
|
|
9
|
+
*
|
|
10
|
+
* @remarks
|
|
11
|
+
* Pre-constructed bundled tools for the `geo_basics` category. Import individually, the whole
|
|
12
|
+
* category, or import every tool via `@nhtio/adk/batteries`.
|
|
13
|
+
*/
|
|
14
|
+
var EARTH_RADIUS_KM = 6371.0088;
|
|
15
|
+
function toRad(deg) {
|
|
16
|
+
return deg * Math.PI / 180;
|
|
17
|
+
}
|
|
18
|
+
function haversineKm(lat1, lon1, lat2, lon2) {
|
|
19
|
+
const dLat = toRad(lat2 - lat1);
|
|
20
|
+
const dLon = toRad(lon2 - lon1);
|
|
21
|
+
const a = Math.sin(dLat / 2) ** 2 + Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLon / 2) ** 2;
|
|
22
|
+
return 2 * EARTH_RADIUS_KM * Math.asin(Math.sqrt(a));
|
|
23
|
+
}
|
|
24
|
+
function validateLatLon(lat, lon, label) {
|
|
25
|
+
if (typeof lat !== "number" || !Number.isFinite(lat) || lat < -90 || lat > 90) return `Error: ${label} latitude must be a number between -90 and 90.`;
|
|
26
|
+
if (typeof lon !== "number" || !Number.isFinite(lon) || lon < -180 || lon > 180) return `Error: ${label} longitude must be a number between -180 and 180.`;
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Great-circle (haversine) distance between two geographic coordinates.
|
|
31
|
+
*
|
|
32
|
+
* @remarks
|
|
33
|
+
* Uses the Earth's mean radius (6371.0088 km). Returns both kilometres and miles.
|
|
34
|
+
*/
|
|
35
|
+
var geoDistanceTool = new Tool({
|
|
36
|
+
name: "geo_distance",
|
|
37
|
+
description: "Calculate the great-circle (haversine) distance between two geographic coordinates. Returns distance in km and miles.",
|
|
38
|
+
inputSchema: validator.object({
|
|
39
|
+
lat1: validator.number().required().description("Latitude of point A (decimal degrees, -90 to 90)"),
|
|
40
|
+
lon1: validator.number().required().description("Longitude of point A (decimal degrees, -180 to 180)"),
|
|
41
|
+
lat2: validator.number().required().description("Latitude of point B (decimal degrees, -90 to 90)"),
|
|
42
|
+
lon2: validator.number().required().description("Longitude of point B (decimal degrees, -180 to 180)")
|
|
43
|
+
}),
|
|
44
|
+
handler: async (args) => {
|
|
45
|
+
const { lat1, lon1, lat2, lon2 } = args;
|
|
46
|
+
const errA = validateLatLon(lat1, lon1, "point A");
|
|
47
|
+
if (errA) return errA;
|
|
48
|
+
const errB = validateLatLon(lat2, lon2, "point B");
|
|
49
|
+
if (errB) return errB;
|
|
50
|
+
const km = haversineKm(lat1, lon1, lat2, lon2);
|
|
51
|
+
const miles = km * .621371;
|
|
52
|
+
return `Distance: ${km.toFixed(4)} km / ${miles.toFixed(4)} miles`;
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
/**
|
|
56
|
+
* Check whether a point lies within a radius of a centre coordinate.
|
|
57
|
+
*
|
|
58
|
+
* @remarks
|
|
59
|
+
* Uses the haversine distance internally; returns the radius unit chosen by the caller
|
|
60
|
+
* (km or miles) in the result string.
|
|
61
|
+
*/
|
|
62
|
+
var geoWithinRadiusTool = new Tool({
|
|
63
|
+
name: "geo_within_radius",
|
|
64
|
+
description: "Check whether a point is within a given radius (km or miles) of a center coordinate.",
|
|
65
|
+
inputSchema: validator.object({
|
|
66
|
+
center_lat: validator.number().required().description("Center latitude"),
|
|
67
|
+
center_lon: validator.number().required().description("Center longitude"),
|
|
68
|
+
point_lat: validator.number().required().description("Point latitude to test"),
|
|
69
|
+
point_lon: validator.number().required().description("Point longitude to test"),
|
|
70
|
+
radius: validator.number().required().description("Radius value (must be positive)"),
|
|
71
|
+
unit: validator.string().valid("km", "miles").default("km").description("Unit for the radius (default: km)")
|
|
72
|
+
}),
|
|
73
|
+
handler: async (args) => {
|
|
74
|
+
const { center_lat: centerLat, center_lon: centerLon, point_lat: pointLat, point_lon: pointLon, radius, unit } = args;
|
|
75
|
+
const errC = validateLatLon(centerLat, centerLon, "center");
|
|
76
|
+
if (errC) return errC;
|
|
77
|
+
const errP = validateLatLon(pointLat, pointLon, "point");
|
|
78
|
+
if (errP) return errP;
|
|
79
|
+
if (!Number.isFinite(radius) || radius <= 0) return "Error: radius must be a positive number.";
|
|
80
|
+
const km = haversineKm(centerLat, centerLon, pointLat, pointLon);
|
|
81
|
+
const distInUnit = unit === "miles" ? km * .621371 : km;
|
|
82
|
+
return `${distInUnit <= radius ? "Yes" : "No"} — distance is ${distInUnit.toFixed(4)} ${unit} (radius: ${radius} ${unit})`;
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
/**
|
|
86
|
+
* Check whether a point falls inside an axis-aligned bounding box.
|
|
87
|
+
*
|
|
88
|
+
* @remarks
|
|
89
|
+
* The bounding box is defined by its SW and NE corners. Boxes that wrap the antimeridian
|
|
90
|
+
* (i.e. SW longitude greater than NE longitude) are handled correctly.
|
|
91
|
+
*/
|
|
92
|
+
var geoBboxContainsTool = new Tool({
|
|
93
|
+
name: "geo_bbox_contains",
|
|
94
|
+
description: "Check whether a point falls inside an axis-aligned bounding box defined by its SW and NE corners.",
|
|
95
|
+
inputSchema: validator.object({
|
|
96
|
+
sw_lat: validator.number().required().description("South-west corner latitude"),
|
|
97
|
+
sw_lon: validator.number().required().description("South-west corner longitude"),
|
|
98
|
+
ne_lat: validator.number().required().description("North-east corner latitude"),
|
|
99
|
+
ne_lon: validator.number().required().description("North-east corner longitude"),
|
|
100
|
+
point_lat: validator.number().required().description("Point latitude to test"),
|
|
101
|
+
point_lon: validator.number().required().description("Point longitude to test")
|
|
102
|
+
}),
|
|
103
|
+
handler: async (args) => {
|
|
104
|
+
const { sw_lat: swLat, sw_lon: swLon, ne_lat: neLat, ne_lon: neLon, point_lat: pointLat, point_lon: pointLon } = args;
|
|
105
|
+
for (const [lat, lon, label] of [
|
|
106
|
+
[
|
|
107
|
+
swLat,
|
|
108
|
+
swLon,
|
|
109
|
+
"SW"
|
|
110
|
+
],
|
|
111
|
+
[
|
|
112
|
+
neLat,
|
|
113
|
+
neLon,
|
|
114
|
+
"NE"
|
|
115
|
+
],
|
|
116
|
+
[
|
|
117
|
+
pointLat,
|
|
118
|
+
pointLon,
|
|
119
|
+
"point"
|
|
120
|
+
]
|
|
121
|
+
]) {
|
|
122
|
+
const err = validateLatLon(lat, lon, label);
|
|
123
|
+
if (err) return err;
|
|
124
|
+
}
|
|
125
|
+
if (swLat > neLat) return "Error: SW latitude must be ≤ NE latitude.";
|
|
126
|
+
return pointLat >= swLat && pointLat <= neLat && (swLon <= neLon ? pointLon >= swLon && pointLon <= neLon : pointLon >= swLon || pointLon <= neLon) ? `Yes — point (${pointLat}, ${pointLon}) is inside the bounding box.` : `No — point (${pointLat}, ${pointLon}) is outside the bounding box.`;
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
//#endregion
|
|
130
|
+
export { geoBboxContainsTool, geoDistanceTool, geoWithinRadiusTool };
|
|
131
|
+
|
|
132
|
+
//# sourceMappingURL=geo_basics.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geo_basics.mjs","names":[],"sources":["../../../src/batteries/tools/geo_basics/index.ts"],"sourcesContent":["/**\n * Pre-constructed tools for basic geographic distance and coordinate calculations.\n *\n * @module @nhtio/adk/batteries/tools/geo_basics\n *\n * @remarks\n * Pre-constructed bundled tools for the `geo_basics` category. Import individually, the whole\n * category, or import every tool via `@nhtio/adk/batteries`.\n */\n\nimport { Tool } from '@nhtio/adk/common'\nimport { validator } from '@nhtio/validation'\n\nconst EARTH_RADIUS_KM = 6371.0088\n\nfunction toRad(deg: number): number {\n return (deg * Math.PI) / 180\n}\n\nfunction haversineKm(lat1: number, lon1: number, lat2: number, lon2: number): number {\n const dLat = toRad(lat2 - lat1)\n const dLon = toRad(lon2 - lon1)\n const a =\n Math.sin(dLat / 2) ** 2 +\n Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLon / 2) ** 2\n return 2 * EARTH_RADIUS_KM * Math.asin(Math.sqrt(a))\n}\n\nfunction validateLatLon(lat: unknown, lon: unknown, label: string): string | null {\n if (typeof lat !== 'number' || !Number.isFinite(lat) || lat < -90 || lat > 90)\n return `Error: ${label} latitude must be a number between -90 and 90.`\n if (typeof lon !== 'number' || !Number.isFinite(lon) || lon < -180 || lon > 180)\n return `Error: ${label} longitude must be a number between -180 and 180.`\n return null\n}\n\n/**\n * Great-circle (haversine) distance between two geographic coordinates.\n *\n * @remarks\n * Uses the Earth's mean radius (6371.0088 km). Returns both kilometres and miles.\n */\nexport const geoDistanceTool = new Tool({\n name: 'geo_distance',\n description:\n 'Calculate the great-circle (haversine) distance between two geographic coordinates. Returns distance in km and miles.',\n inputSchema: validator.object({\n lat1: validator\n .number()\n .required()\n .description('Latitude of point A (decimal degrees, -90 to 90)'),\n lon1: validator\n .number()\n .required()\n .description('Longitude of point A (decimal degrees, -180 to 180)'),\n lat2: validator\n .number()\n .required()\n .description('Latitude of point B (decimal degrees, -90 to 90)'),\n lon2: validator\n .number()\n .required()\n .description('Longitude of point B (decimal degrees, -180 to 180)'),\n }),\n handler: async (args) => {\n const { lat1, lon1, lat2, lon2 } = args as {\n lat1: number\n lon1: number\n lat2: number\n lon2: number\n }\n\n const errA = validateLatLon(lat1, lon1, 'point A')\n if (errA) return errA\n const errB = validateLatLon(lat2, lon2, 'point B')\n if (errB) return errB\n\n const km = haversineKm(lat1, lon1, lat2, lon2)\n const miles = km * 0.621371\n\n return `Distance: ${km.toFixed(4)} km / ${miles.toFixed(4)} miles`\n },\n})\n\n/**\n * Check whether a point lies within a radius of a centre coordinate.\n *\n * @remarks\n * Uses the haversine distance internally; returns the radius unit chosen by the caller\n * (km or miles) in the result string.\n */\nexport const geoWithinRadiusTool = new Tool({\n name: 'geo_within_radius',\n description:\n 'Check whether a point is within a given radius (km or miles) of a center coordinate.',\n inputSchema: validator.object({\n center_lat: validator.number().required().description('Center latitude'),\n center_lon: validator.number().required().description('Center longitude'),\n point_lat: validator.number().required().description('Point latitude to test'),\n point_lon: validator.number().required().description('Point longitude to test'),\n radius: validator.number().required().description('Radius value (must be positive)'),\n unit: validator\n .string()\n .valid('km', 'miles')\n .default('km')\n .description('Unit for the radius (default: km)'),\n }),\n handler: async (args) => {\n const {\n center_lat: centerLat,\n center_lon: centerLon,\n point_lat: pointLat,\n point_lon: pointLon,\n radius,\n unit,\n } = args as {\n center_lat: number\n center_lon: number\n point_lat: number\n point_lon: number\n radius: number\n unit: string\n }\n\n const errC = validateLatLon(centerLat, centerLon, 'center')\n if (errC) return errC\n const errP = validateLatLon(pointLat, pointLon, 'point')\n if (errP) return errP\n if (!Number.isFinite(radius) || radius <= 0) return 'Error: radius must be a positive number.'\n\n const km = haversineKm(centerLat, centerLon, pointLat, pointLon)\n const distInUnit = unit === 'miles' ? km * 0.621371 : km\n const within = distInUnit <= radius\n\n return `${within ? 'Yes' : 'No'} — distance is ${distInUnit.toFixed(4)} ${unit} (radius: ${radius} ${unit})`\n },\n})\n\n/**\n * Check whether a point falls inside an axis-aligned bounding box.\n *\n * @remarks\n * The bounding box is defined by its SW and NE corners. Boxes that wrap the antimeridian\n * (i.e. SW longitude greater than NE longitude) are handled correctly.\n */\nexport const geoBboxContainsTool = new Tool({\n name: 'geo_bbox_contains',\n description:\n 'Check whether a point falls inside an axis-aligned bounding box defined by its SW and NE corners.',\n inputSchema: validator.object({\n sw_lat: validator.number().required().description('South-west corner latitude'),\n sw_lon: validator.number().required().description('South-west corner longitude'),\n ne_lat: validator.number().required().description('North-east corner latitude'),\n ne_lon: validator.number().required().description('North-east corner longitude'),\n point_lat: validator.number().required().description('Point latitude to test'),\n point_lon: validator.number().required().description('Point longitude to test'),\n }),\n handler: async (args) => {\n const {\n sw_lat: swLat,\n sw_lon: swLon,\n ne_lat: neLat,\n ne_lon: neLon,\n point_lat: pointLat,\n point_lon: pointLon,\n } = args as {\n sw_lat: number\n sw_lon: number\n ne_lat: number\n ne_lon: number\n point_lat: number\n point_lon: number\n }\n\n for (const [lat, lon, label] of [\n [swLat, swLon, 'SW'],\n [neLat, neLon, 'NE'],\n [pointLat, pointLon, 'point'],\n ] as [number, number, string][]) {\n const err = validateLatLon(lat, lon, label)\n if (err) return err\n }\n\n if (swLat > neLat) return 'Error: SW latitude must be ≤ NE latitude.'\n\n const latIn = pointLat >= swLat && pointLat <= neLat\n\n // Handle bounding boxes that wrap the antimeridian\n const lonIn =\n swLon <= neLon\n ? pointLon >= swLon && pointLon <= neLon\n : pointLon >= swLon || pointLon <= neLon\n\n const inside = latIn && lonIn\n return inside\n ? `Yes — point (${pointLat}, ${pointLon}) is inside the bounding box.`\n : `No — point (${pointLat}, ${pointLon}) is outside the bounding box.`\n },\n})\n"],"mappings":"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"}
|