@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 @@
|
|
|
1
|
+
{"version":3,"file":"spooled_markdown_artifact-RRB113sy.js","names":["#format","#resolveFormat","#resolveRecords","#parsed","#resolveIndex","#index","#frontmatter"],"sources":["../src/lib/classes/spooled_json_artifact.ts","../src/lib/classes/spooled_markdown_artifact.ts"],"sourcesContent":["import { default as JSON5 } from 'json5'\nimport { JSONPath } from 'jsonpath-plus'\nimport { validator } from '@nhtio/validation'\nimport { ArtifactTool } from './artifact_tool'\nimport { ToolRegistry } from './tool_registry'\nimport { isInstanceOf, isObject } from '../utils/guards'\nimport { SpooledArtifact, defaultSerialise } from './spooled_artifact'\nimport type { SpoolReader } from '../contracts/spool_reader'\nimport type { ToolMethodDescriptor } from './spooled_artifact'\nimport type { DispatchContext } from '../contracts/dispatch_context'\n\n/**\n * The set of JSON-derived formats that {@link SpooledJsonArtifact} can handle.\n *\n * @remarks\n * - `json` — a single JSON value spanning the entire artifact (strict RFC 8259).\n * - `json5` — a single JSON5 value spanning the entire artifact; permits comments, trailing\n * commas, unquoted keys, and other relaxed syntax via the `json5` package.\n * - `jsonl` — newline-delimited JSON; each non-empty line is an independent JSON value.\n * - `ndjson` — alias for `jsonl`; both names are accepted and behave identically.\n */\nexport type JsonArtifactFormat = 'json' | 'json5' | 'jsonl' | 'ndjson'\n\n/**\n * Detects the {@link JsonArtifactFormat} of a raw string.\n *\n * @remarks\n * Detection strategy (in order):\n * 1. If the content parses as strict JSON → `json`.\n * 2. If every non-empty line parses as strict JSON → `jsonl`.\n * 3. If the content parses as JSON5 → `json5`.\n * 4. Otherwise throws.\n *\n * Strict JSON is tried before JSON5 so that well-formed JSON files are not unnecessarily\n * classified as JSON5.\n *\n * @param content - The full artifact text to inspect.\n * @returns The inferred format.\n * @throws `Error` when the content cannot be classified as any supported JSON format.\n */\nfunction inferFormat(content: string): JsonArtifactFormat {\n const trimmed = content.trim()\n\n // 1. Try strict JSON\n try {\n JSON.parse(trimmed)\n return 'json'\n } catch {\n // fall through\n }\n\n // 2. Try JSONL (every non-empty line is valid JSON)\n const nonEmptyLines = trimmed.split('\\n').filter((l) => l.trim().length > 0)\n if (\n nonEmptyLines.length > 0 &&\n nonEmptyLines.every((l) => {\n try {\n JSON.parse(l)\n return true\n } catch {\n return false\n }\n })\n ) {\n return 'jsonl'\n }\n\n // 3. Try JSON5\n try {\n JSON5.parse(trimmed)\n return 'json5'\n } catch {\n // fall through\n }\n\n throw new Error('Unable to infer JSON format: content is not valid JSON, JSONL, NDJSON, or JSON5')\n}\n\n/**\n * A {@link @nhtio/adk!SpooledArtifact} specialisation that adds JSON-aware read operations.\n *\n * @typeParam T - The expected shape of each parsed record. Defaults to `unknown`.\n *\n * @remarks\n * Construct with an optional `format` hint. When omitted the format is auto-detected on first\n * access by reading the full artifact and running {@link inferFormat}. Once detected (or\n * provided), the format is cached for the lifetime of the instance.\n *\n * All JSON methods are async, consistent with {@link @nhtio/adk!SpooledArtifact}.\n *\n * Path-based methods (`json_get`, `json_filter`, `json_pluck`) use\n * [JSONPath-Plus](https://github.com/JSONPath-Plus/JSONPath) expressions. Full JSONPath syntax\n * is supported, including recursive descent (`..`), filter expressions (`[?(@.age > 18)]`),\n * and union selectors.\n */\nexport class SpooledJsonArtifact<T = unknown> extends SpooledArtifact {\n #format: JsonArtifactFormat | undefined\n #parsed: T[] | undefined\n\n /**\n * @param reader - The backing store to read from.\n * @param format - Optional format hint. When omitted, the format is inferred on first access.\n */\n constructor(reader: SpoolReader, format?: JsonArtifactFormat) {\n super(reader)\n this.#format = format\n }\n\n /**\n * Returns `true` if `value` is a {@link SpooledJsonArtifact} instance.\n *\n * @remarks\n * Uses the cross-realm-safe {@link @nhtio/adk!isInstanceOf} guard: `instanceof` first, then\n * `Symbol.hasInstance`, then a `constructor.name` fallback. Matches the pattern used by every\n * other class guard in the ADK; safe against the dual-module-copy case where two distinct\n * `SpooledJsonArtifact` classes coexist in the same realm.\n *\n * @param value - The value to test.\n * @returns `true` when `value` is a {@link SpooledJsonArtifact} instance.\n */\n public static isSpooledJsonArtifact(value: unknown): value is SpooledJsonArtifact {\n return isInstanceOf(value, 'SpooledJsonArtifact', SpooledJsonArtifact)\n }\n\n /**\n * The JSON-specific artifact-query descriptors this class adds on top of the base set.\n *\n * @remarks\n * Lists `artifact_json_type`, `artifact_json_keys`, `artifact_json_length`,\n * `artifact_json_get`, `artifact_json_filter`, `artifact_json_slice`, `artifact_json_pluck`.\n * The base seven descriptors (`artifact_head`, etc.) are NOT included here — they are\n * forged separately by {@link SpooledJsonArtifact.forgeTools}, which calls\n * `SpooledArtifact.forgeTools(ctx)` to produce the base-narrowed tools and then registers\n * its own JSON tools on the result. Downstream consumers building custom subclasses\n * should follow the same pattern: own only your own descriptors; override `forgeTools` to\n * compose with the base output.\n */\n public static toolMethods: ReadonlyArray<ToolMethodDescriptor> = Object.freeze([\n {\n name: 'artifact_json_type',\n method: 'json_type',\n description:\n 'Return the JSON format (json | json5 | jsonl | ndjson) of a JSON artifact produced earlier in this turn.',\n argsSchema: validator.object({}),\n },\n {\n name: 'artifact_json_keys',\n method: 'json_keys',\n description: 'Return the top-level keys of a JSON artifact produced earlier in this turn.',\n argsSchema: validator.object({}),\n },\n {\n name: 'artifact_json_length',\n method: 'json_length',\n description:\n 'Return the record count of a JSON artifact produced earlier in this turn (1 for json/json5; line count for jsonl/ndjson).',\n argsSchema: validator.object({}),\n },\n {\n name: 'artifact_json_get',\n method: 'json_get',\n description:\n 'Evaluate a JSONPath expression against a JSON artifact produced earlier in this turn.',\n argsSchema: validator.object({\n path: validator.string().required().description(\"JSONPath expression, e.g. '$.user.name'.\"),\n }),\n },\n {\n name: 'artifact_json_filter',\n method: 'json_filter',\n description:\n 'Return records of a JSON artifact (produced earlier in this turn) matched by a JSONPath filter.',\n argsSchema: validator.object({\n path: validator\n .string()\n .required()\n .description(\"JSONPath filter expression, e.g. '$[?(@.age>18)]'.\"),\n }),\n },\n {\n name: 'artifact_json_slice',\n method: 'json_slice',\n description:\n 'Return a slice of records by index range from a JSON artifact produced earlier in this turn.',\n argsSchema: validator.object({\n start: validator\n .number()\n .integer()\n .min(0)\n .optional()\n .description('Start index (inclusive).'),\n end: validator.number().integer().min(0).optional().description('End index (exclusive).'),\n }),\n },\n {\n name: 'artifact_json_pluck',\n method: 'json_pluck',\n description:\n 'Return all values matched by a JSONPath expression across every record of a JSON artifact produced earlier in this turn.',\n argsSchema: validator.object({\n path: validator.string().required().description(\"JSONPath expression, e.g. '$..name'.\"),\n }),\n },\n ])\n\n /**\n * Forges base-class tools plus JSON-specific tools narrowed to {@link SpooledJsonArtifact}.\n *\n * @remarks\n * Standard subclass extension pattern: call `SpooledArtifact.forgeTools(ctx)` to produce\n * the base seven `artifact_*` tools narrowed to any `SpooledArtifact` in the turn, then\n * register one `ArtifactTool` per JSON-specific descriptor narrowed to JSON artifacts.\n * Downstream consumers building their own subclasses should follow the same shape.\n */\n public static override forgeTools(ctx: DispatchContext): ToolRegistry {\n const registry = SpooledArtifact.forgeTools(ctx)\n const requires = SpooledJsonArtifact\n const compatibleIds = [...ctx.turnToolCalls]\n .filter((tc) => !tc.fromArtifactTool && isInstanceOf(tc.results, requires.name, requires))\n .map((tc) => tc.id)\n if (compatibleIds.length === 0) return registry\n\n for (const descriptor of this.toolMethods) {\n const callIdSchema = validator\n .string()\n .valid(...compatibleIds)\n .required()\n .description('ToolCall id of the artifact to query.')\n\n const argsSchema = (\n descriptor.argsSchema ?? validator.object<Record<string, never>>({})\n ).append({\n callId: callIdSchema,\n })\n\n const tool = new ArtifactTool({\n name: descriptor.name,\n description: descriptor.description,\n inputSchema: argsSchema,\n ephemeral: true,\n onCollision: 'replace',\n handler: async (rawArgs, ctxInner) => {\n const args = rawArgs as Record<string, unknown> & { callId: string }\n const tc = [...ctxInner.turnToolCalls].find((t) => t.id === args.callId)\n if (!tc) {\n return `Error: no tool call with id ${args.callId} in this turn`\n }\n const artifact = tc.results\n if (!isInstanceOf(artifact, requires.name, requires)) {\n return `Error: tool call ${args.callId} results are not a ${requires.name} instance`\n }\n const methodArgs: unknown[] = []\n if (\n descriptor.method === 'json_get' ||\n descriptor.method === 'json_filter' ||\n descriptor.method === 'json_pluck'\n ) {\n methodArgs.push(args.path as string)\n } else if (descriptor.method === 'json_slice') {\n methodArgs.push(args.start as number | undefined, args.end as number | undefined)\n }\n const fn = (artifact as unknown as Record<string, (...a: unknown[]) => unknown>)[\n descriptor.method\n ]\n if (typeof fn !== 'function') {\n return `Error: artifact has no method ${descriptor.method}`\n }\n const result = await Promise.resolve(fn.apply(artifact, methodArgs))\n const serialise = descriptor.serialise ?? defaultSerialise\n return serialise(result)\n },\n })\n registry.register(tool)\n }\n return registry\n }\n\n /**\n * Resolves and caches the detected or provided format.\n */\n async #resolveFormat(): Promise<JsonArtifactFormat> {\n if (this.#format !== undefined) {\n return this.#format\n }\n const lines = await this.cat()\n this.#format = inferFormat(lines.join('\\n'))\n return this.#format\n }\n\n /**\n * Parses and caches all records from the artifact.\n *\n * @remarks\n * For `json`/`json5` format: returns a single-element array containing the parsed root value.\n * For `jsonl`/`ndjson` format: returns one element per non-empty line.\n */\n async #resolveRecords(): Promise<T[]> {\n if (this.#parsed !== undefined) {\n return this.#parsed\n }\n const format = await this.#resolveFormat()\n const lines = await this.cat()\n if (format === 'json') {\n this.#parsed = [JSON.parse(lines.join('\\n')) as T]\n } else if (format === 'json5') {\n this.#parsed = [JSON5.parse(lines.join('\\n')) as T]\n } else {\n // jsonl / ndjson\n this.#parsed = lines.filter((l) => l.trim().length > 0).map((l) => JSON.parse(l) as T)\n }\n return this.#parsed\n }\n\n /**\n * Returns the detected or provided format for this artifact.\n *\n * @returns One of `'json'`, `'json5'`, `'jsonl'`, or `'ndjson'`.\n */\n async json_type(): Promise<JsonArtifactFormat> {\n return this.#resolveFormat()\n }\n\n /**\n * Returns the top-level keys of the parsed content.\n *\n * @remarks\n * - For `json`/`json5`: returns the keys of the root object, or `undefined` when the root is\n * not a plain object (e.g. an array or scalar).\n * - For `jsonl`/`ndjson`: returns the union of keys across all records that are plain objects.\n * Duplicate keys are deduplicated.\n *\n * @returns Array of key strings, or `undefined` when no object keys are present.\n */\n async json_keys(): Promise<string[] | undefined> {\n const records = await this.#resolveRecords()\n const format = await this.#resolveFormat()\n if (format === 'json' || format === 'json5') {\n const root = records[0]\n if (isObject(root)) {\n return Object.keys(root as object)\n }\n return undefined\n }\n const keySet = new Set<string>()\n for (const record of records) {\n if (isObject(record)) {\n for (const key of Object.keys(record as object)) {\n keySet.add(key)\n }\n }\n }\n return keySet.size > 0 ? Array.from(keySet) : undefined\n }\n\n /**\n * Returns the total number of records in the artifact.\n *\n * @remarks\n * - For `json`/`json5`: always `1` (the entire artifact is a single value).\n * - For `jsonl`/`ndjson`: the number of non-empty lines.\n *\n * @returns The record count.\n */\n async json_length(): Promise<number> {\n const records = await this.#resolveRecords()\n return records.length\n }\n\n /**\n * Evaluates a JSONPath expression against the parsed content.\n *\n * @remarks\n * Uses [JSONPath-Plus](https://github.com/JSONPath-Plus/JSONPath). Full JSONPath syntax is\n * supported: recursive descent (`$..*`), filter expressions (`$[?(@.age > 18)]`), union\n * selectors, and more.\n *\n * - For `json`/`json5`: evaluates the expression against the root value.\n * - For `jsonl`/`ndjson`: evaluates the expression against each record and returns a flat\n * array of all matches across all records.\n *\n * @param path - A JSONPath expression (e.g. `'$.user.address.city'`, `'$..name'`).\n * @returns Array of matched values. Empty array when no matches are found.\n */\n async json_get(path: string): Promise<unknown[]> {\n const records = await this.#resolveRecords()\n const format = await this.#resolveFormat()\n if (format === 'json' || format === 'json5') {\n return JSONPath({ path, json: records[0] as object })\n }\n return records.flatMap((r) => JSONPath({ path, json: r as object }))\n }\n\n /**\n * Returns a slice of the parsed records by index range.\n *\n * @remarks\n * For `json`/`json5`: always returns `[root]` — the artifact is a single record so slicing is\n * not meaningful. For `jsonl`/`ndjson`: behaves like `Array.prototype.slice`.\n *\n * @param start - Start index (inclusive). Defaults to `0`.\n * @param end - End index (exclusive). Defaults to the record count.\n * @returns Array of sliced records.\n */\n async json_slice(start?: number, end?: number): Promise<T[]> {\n const records = await this.#resolveRecords()\n const format = await this.#resolveFormat()\n if (format === 'json' || format === 'json5') {\n return records\n }\n return records.slice(start, end)\n }\n\n /**\n * Returns records matched by a JSONPath filter expression.\n *\n * @remarks\n * Evaluates `path` against each record and returns those for which the expression produces at\n * least one match. For `json`/`json5`, evaluates against the root value and returns it in an\n * array if matched.\n *\n * @param path - A JSONPath expression (e.g. `'$[?(@.status === \"active\")]'`).\n * @returns Array of matching records.\n */\n async json_filter(path: string): Promise<T[]> {\n const records = await this.#resolveRecords()\n return records.filter((r) => {\n const matches = JSONPath({ path, json: r as object })\n return Array.isArray(matches) && matches.length > 0\n })\n }\n\n /**\n * Returns all values matched by a JSONPath expression across every record.\n *\n * @remarks\n * Convenience over {@link SpooledJsonArtifact.json_get} with an identical signature — use\n * whichever name better communicates intent at the call site. `json_pluck` reads well for\n * extracting a single field column; `json_get` reads well for structured queries.\n *\n * @param path - A JSONPath expression (e.g. `'$..name'`).\n * @returns Array of matched values.\n */\n async json_pluck(path: string): Promise<unknown[]> {\n return this.json_get(path)\n }\n}\n","import { remark } from 'remark'\nimport { visit } from 'unist-util-visit'\nimport { load as yamlLoad } from 'js-yaml'\nimport { validator } from '@nhtio/validation'\nimport { isInstanceOf } from '../utils/guards'\nimport { ArtifactTool } from './artifact_tool'\nimport { ToolRegistry } from './tool_registry'\nimport { default as remarkGfm } from 'remark-gfm'\nimport { toString as mdastToString } from 'mdast-util-to-string'\nimport { default as remarkFrontmatter } from 'remark-frontmatter'\nimport { SpooledArtifact, defaultSerialise } from './spooled_artifact'\nimport type { Root, Link, Image } from 'mdast'\nimport type { SpoolReader } from '../contracts/spool_reader'\nimport type { ToolMethodDescriptor } from './spooled_artifact'\nimport type { DispatchContext } from '../contracts/dispatch_context'\n\n/**\n * A single heading entry in the document's structural index.\n *\n * @remarks\n * `startLine` is the 0-based line of the heading itself. `endLine` is the 0-based index of the\n * last line belonging to this section (inclusive) — the line immediately before the next heading\n * of equal or lesser depth, or the last line of the document.\n */\nexport interface MarkdownHeadingEntry {\n /** ATX heading depth: 1 (`#`) through 6 (`######`). */\n depth: 1 | 2 | 3 | 4 | 5 | 6\n /** The heading text with the leading `#` prefix stripped and trimmed. */\n text: string\n /** 0-based line index of the heading line itself. */\n startLine: number\n /** 0-based line index of the last line in this section (inclusive). */\n endLine: number\n}\n\n/**\n * A single fenced code block entry in the document's structural index.\n */\nexport interface MarkdownCodeEntry {\n /** The language identifier immediately after the opening fence, or `null` when absent. */\n lang: string | null\n /** 0-based line index of the opening fence line. */\n startLine: number\n /** 0-based line index of the closing fence line. */\n endLine: number\n}\n\ninterface MarkdownIndex {\n headings: MarkdownHeadingEntry[]\n codeBlocks: MarkdownCodeEntry[]\n}\n\n/**\n * A section of a markdown document as returned by {@link SpooledMarkdownArtifact.md_sections}.\n *\n * @remarks\n * Contains only line-range metadata — no content is fetched until the caller explicitly\n * requests it via `cat(bodyStartLine, bodyEndLine + 1)`.\n */\nexport interface MarkdownSection {\n depth: 1 | 2 | 3 | 4 | 5 | 6\n /** The heading text. */\n heading: string\n /** 0-based line of the heading itself. */\n headingLine: number\n /** 0-based line of the first body line (heading line + 1). */\n bodyStartLine: number\n /** 0-based line of the last body line (inclusive). */\n bodyEndLine: number\n}\n\n/**\n * Returns a configured remark processor with frontmatter and GFM support.\n */\nfunction processor() {\n return remark().use(remarkFrontmatter).use(remarkGfm)\n}\n\n/**\n * Parses a heading line (e.g. `## My Heading`) and returns `{ depth, text }`, or `null` when\n * the line is not an ATX heading.\n */\nfunction parseHeadingLine(line: string): { depth: 1 | 2 | 3 | 4 | 5 | 6; text: string } | null {\n const match = /^(#{1,6})\\s+(.*)$/.exec(line)\n if (!match) return null\n const depth = match[1].length as 1 | 2 | 3 | 4 | 5 | 6\n return { depth, text: match[2].trim() }\n}\n\n/**\n * Returns the length of a fence marker at the start of `line` (3+), or `0` if the line is not\n * a fence opener/closer. Handles both backtick (` ``` `) and tilde (`~~~`) fences.\n */\nfunction fenceLength(line: string): number {\n const trimmed = line.trimStart()\n const match = /^(`{3,}|~{3,})/.exec(trimmed)\n return match ? match[1].length : 0\n}\n\n/**\n * Extracts the language identifier from a fence opener line (e.g. ` ```ts ` → `'ts'`), or\n * `null` when none is present.\n */\nfunction fenceLang(line: string): string | null {\n const trimmed = line.trimStart()\n const match = /^(?:`{3,}|~{3,})(\\S+)/.exec(trimmed)\n return match ? match[1] : null\n}\n\n/**\n * A {@link @nhtio/adk!SpooledArtifact} specialisation that adds markdown-aware structural queries.\n *\n * @remarks\n * Designed for large markdown documents where loading the full content into memory is\n * impractical. The structural index (heading positions, code block positions) is built by a\n * single line-by-line scan of the {@link @nhtio/adk!SpoolReader} without retaining any content. Only the\n * tiny metadata index and the parsed frontmatter object are cached.\n *\n * Content retrieval is always bounded — use `cat(start, end)` or the `startLine`/`endLine`\n * parameters on inline methods to fetch only the lines you need.\n *\n * Inline methods (`md_links`, `md_images`, `md_text`, `md_ast`) accept optional line-range\n * arguments. Without a range they read the full document — documented trade-off, caller\n * responsibility to bound the range for large documents.\n *\n * The processor always applies `remark-gfm` (tables, task lists, strikethrough, autolinks)\n * in addition to standard CommonMark and YAML frontmatter.\n */\nexport class SpooledMarkdownArtifact extends SpooledArtifact {\n #index: MarkdownIndex | undefined\n #frontmatter: Record<string, unknown> | null | undefined\n\n /**\n * @param reader - The backing store to read from.\n */\n constructor(reader: SpoolReader) {\n super(reader)\n }\n\n /**\n * Returns `true` if `value` is a {@link SpooledMarkdownArtifact} instance.\n *\n * @remarks\n * Uses the cross-realm-safe {@link @nhtio/adk!isInstanceOf} guard: `instanceof` first, then\n * `Symbol.hasInstance`, then a `constructor.name` fallback. Matches the pattern used by every\n * other class guard in the ADK; safe against the dual-module-copy case where two distinct\n * `SpooledMarkdownArtifact` classes coexist in the same realm.\n */\n public static isSpooledMarkdownArtifact(value: unknown): value is SpooledMarkdownArtifact {\n return isInstanceOf(value, 'SpooledMarkdownArtifact', SpooledMarkdownArtifact)\n }\n\n /**\n * The markdown-specific artifact-query descriptors this class adds on top of the base set.\n *\n * @remarks\n * Lists `artifact_md_frontmatter`, `artifact_md_headings`, `artifact_md_code_blocks`,\n * `artifact_md_sections`, `artifact_md_links`, `artifact_md_images`, `artifact_md_text`,\n * `artifact_md_ast`. The base seven descriptors (`artifact_head`, etc.) are NOT included\n * here — they are forged separately by {@link SpooledMarkdownArtifact.forgeTools}, which\n * calls `SpooledArtifact.forgeTools(ctx)` to produce the base-narrowed tools and then\n * registers its own markdown tools on the result. Downstream consumers building custom\n * subclasses should follow the same pattern: own only your own descriptors; override\n * `forgeTools` to compose with the base output.\n */\n public static toolMethods: ReadonlyArray<ToolMethodDescriptor> = Object.freeze([\n {\n name: 'artifact_md_frontmatter',\n method: 'md_frontmatter',\n description:\n 'Return parsed YAML frontmatter (or undefined) from a markdown artifact produced earlier in this turn.',\n argsSchema: validator.object({}),\n },\n {\n name: 'artifact_md_headings',\n method: 'md_headings',\n description:\n 'Return all headings, optionally filtered by depth, from a markdown artifact produced earlier in this turn.',\n argsSchema: validator.object({\n depth: validator\n .number()\n .integer()\n .min(1)\n .max(6)\n .optional()\n .description('ATX heading depth (1-6).'),\n }),\n },\n {\n name: 'artifact_md_code_blocks',\n method: 'md_code_blocks',\n description:\n 'Return all fenced code block entries, optionally filtered by language, from a markdown artifact produced earlier in this turn.',\n argsSchema: validator.object({\n lang: validator\n .string()\n .optional()\n .description('Language identifier. Pass empty string to match blocks with no lang.'),\n }),\n },\n {\n name: 'artifact_md_sections',\n method: 'md_sections',\n description:\n 'Return document sections (line-range metadata only) from a markdown artifact produced earlier in this turn.',\n argsSchema: validator.object({\n depth: validator\n .number()\n .integer()\n .min(1)\n .max(6)\n .optional()\n .description('ATX heading depth (1-6).'),\n }),\n },\n {\n name: 'artifact_md_links',\n method: 'md_links',\n description:\n 'Return all inline and reference links within the given line range from a markdown artifact produced earlier in this turn.',\n argsSchema: validator.object({\n startLine: validator\n .number()\n .integer()\n .min(0)\n .optional()\n .description('Start line (inclusive).'),\n endLine: validator\n .number()\n .integer()\n .min(0)\n .optional()\n .description('End line (exclusive).'),\n }),\n },\n {\n name: 'artifact_md_images',\n method: 'md_images',\n description:\n 'Return all images within the given line range from a markdown artifact produced earlier in this turn.',\n argsSchema: validator.object({\n startLine: validator\n .number()\n .integer()\n .min(0)\n .optional()\n .description('Start line (inclusive).'),\n endLine: validator\n .number()\n .integer()\n .min(0)\n .optional()\n .description('End line (exclusive).'),\n }),\n },\n {\n name: 'artifact_md_text',\n method: 'md_text',\n description:\n 'Return plain text with markup stripped, for the given line range, from a markdown artifact produced earlier in this turn.',\n argsSchema: validator.object({\n startLine: validator\n .number()\n .integer()\n .min(0)\n .optional()\n .description('Start line (inclusive).'),\n endLine: validator\n .number()\n .integer()\n .min(0)\n .optional()\n .description('End line (exclusive).'),\n }),\n },\n {\n name: 'artifact_md_ast',\n method: 'md_ast',\n description:\n 'Return the full MDAST Root for the specified line range from a markdown artifact produced earlier in this turn.',\n argsSchema: validator.object({\n startLine: validator\n .number()\n .integer()\n .min(0)\n .optional()\n .description('Start line (inclusive).'),\n endLine: validator\n .number()\n .integer()\n .min(0)\n .optional()\n .description('End line (exclusive).'),\n }),\n },\n ])\n\n /**\n * Forges base-class tools plus markdown-specific tools narrowed to\n * {@link SpooledMarkdownArtifact}.\n *\n * @remarks\n * Standard subclass extension pattern: call `SpooledArtifact.forgeTools(ctx)` to produce\n * the base seven `artifact_*` tools narrowed to any `SpooledArtifact` in the turn, then\n * register one `ArtifactTool` per markdown-specific descriptor narrowed to markdown\n * artifacts. Downstream consumers building their own subclasses should follow the same\n * shape.\n */\n public static override forgeTools(ctx: DispatchContext): ToolRegistry {\n const registry = SpooledArtifact.forgeTools(ctx)\n const requires = SpooledMarkdownArtifact\n const compatibleIds = [...ctx.turnToolCalls]\n .filter((tc) => !tc.fromArtifactTool && isInstanceOf(tc.results, requires.name, requires))\n .map((tc) => tc.id)\n if (compatibleIds.length === 0) return registry\n\n for (const descriptor of this.toolMethods) {\n const callIdSchema = validator\n .string()\n .valid(...compatibleIds)\n .required()\n .description('ToolCall id of the artifact to query.')\n\n const argsSchema = (\n descriptor.argsSchema ?? validator.object<Record<string, never>>({})\n ).append({\n callId: callIdSchema,\n })\n\n const tool = new ArtifactTool({\n name: descriptor.name,\n description: descriptor.description,\n inputSchema: argsSchema,\n ephemeral: true,\n onCollision: 'replace',\n handler: async (rawArgs, ctxInner) => {\n const args = rawArgs as Record<string, unknown> & { callId: string }\n const tc = [...ctxInner.turnToolCalls].find((t) => t.id === args.callId)\n if (!tc) {\n return `Error: no tool call with id ${args.callId} in this turn`\n }\n const artifact = tc.results\n if (!isInstanceOf(artifact, requires.name, requires)) {\n return `Error: tool call ${args.callId} results are not a ${requires.name} instance`\n }\n const methodArgs: unknown[] = []\n if (descriptor.method === 'md_headings' || descriptor.method === 'md_sections') {\n methodArgs.push(args.depth as number | undefined)\n } else if (descriptor.method === 'md_code_blocks') {\n methodArgs.push(args.lang as string | undefined)\n } else if (\n descriptor.method === 'md_links' ||\n descriptor.method === 'md_images' ||\n descriptor.method === 'md_text' ||\n descriptor.method === 'md_ast'\n ) {\n methodArgs.push(\n args.startLine as number | undefined,\n args.endLine as number | undefined\n )\n }\n const fn = (artifact as unknown as Record<string, (...a: unknown[]) => unknown>)[\n descriptor.method\n ]\n if (typeof fn !== 'function') {\n return `Error: artifact has no method ${descriptor.method}`\n }\n const result = await Promise.resolve(fn.apply(artifact, methodArgs))\n const serialise = descriptor.serialise ?? defaultSerialise\n return serialise(result)\n },\n })\n registry.register(tool)\n }\n return registry\n }\n\n /**\n * Builds the structural index in a single top-to-bottom pass, retaining only metadata.\n */\n async #resolveIndex(): Promise<MarkdownIndex> {\n if (this.#index !== undefined) return this.#index\n\n const count = await this.lineCount()\n const headingsRaw: Array<{ depth: 1 | 2 | 3 | 4 | 5 | 6; text: string; startLine: number }> = []\n const codeBlocks: MarkdownCodeEntry[] = []\n\n let inFrontmatter = false\n let frontmatterClosed = false\n let inCodeBlock = false\n let openFenceLen = 0\n let openFenceStartLine = 0\n let openFenceLang: string | null = null\n\n for (let i = 0; i < count; i++) {\n const rawLine = await this.line(i)\n const l = rawLine ?? ''\n\n // Handle frontmatter block at the top of the document\n if (i === 0 && l.trim() === '---') {\n inFrontmatter = true\n continue\n }\n if (inFrontmatter) {\n if (l.trim() === '---') {\n inFrontmatter = false\n frontmatterClosed = true\n }\n continue\n }\n if (!frontmatterClosed && i === 0) {\n // No frontmatter — treat as normal document from the start\n }\n\n // Handle fenced code blocks\n const fLen = fenceLength(l)\n if (!inCodeBlock && fLen >= 3) {\n inCodeBlock = true\n openFenceLen = fLen\n openFenceStartLine = i\n openFenceLang = fenceLang(l)\n continue\n }\n if (inCodeBlock) {\n // A closing fence must use the same fence character (` or ~) and be at least as long.\n if (fLen >= openFenceLen) {\n const openLine = (await this.line(openFenceStartLine)) ?? ''\n const openChar = openLine.trimStart()[0]\n const closeChar = l.trimStart()[0]\n if (closeChar === openChar) {\n codeBlocks.push({ lang: openFenceLang, startLine: openFenceStartLine, endLine: i })\n inCodeBlock = false\n openFenceLen = 0\n }\n }\n continue\n }\n\n // Detect ATX headings (not inside code blocks, not in frontmatter)\n const heading = parseHeadingLine(l)\n if (heading) {\n headingsRaw.push({ ...heading, startLine: i })\n }\n }\n\n // Unclosed code block — record it anyway\n if (inCodeBlock) {\n codeBlocks.push({ lang: openFenceLang, startLine: openFenceStartLine, endLine: count - 1 })\n }\n\n // Post-process heading endLine values\n const headings: MarkdownHeadingEntry[] = headingsRaw.map((h, idx) => {\n const nextBoundary = headingsRaw.slice(idx + 1).find((n) => n.depth <= h.depth)\n const endLine = nextBoundary ? nextBoundary.startLine - 1 : count - 1\n return { ...h, endLine }\n })\n\n this.#index = { headings, codeBlocks }\n return this.#index\n }\n\n // ── Frontmatter ───────────────────────────────────────────────────────────\n\n /**\n * Returns the parsed YAML frontmatter, or `undefined` when no frontmatter block is present.\n *\n * @remarks\n * Short-circuits after reading the frontmatter block — never reads the document body. Caches\n * the result so subsequent calls are free. The result is `undefined` (not an empty object)\n * when no frontmatter is found, distinguishing \"no frontmatter\" from \"empty frontmatter\".\n */\n async md_frontmatter(): Promise<Record<string, unknown> | undefined> {\n if (this.#frontmatter !== undefined) return this.#frontmatter ?? undefined\n\n const firstLine = await this.line(0)\n if (firstLine?.trim() !== '---') {\n this.#frontmatter = null\n return undefined\n }\n\n const maxScan = Math.min(await this.lineCount(), 200)\n const yamlLines: string[] = []\n let closed = false\n for (let i = 1; i < maxScan; i++) {\n const l = await this.line(i)\n if (l?.trim() === '---') {\n closed = true\n break\n }\n yamlLines.push(l ?? '')\n }\n\n if (!closed) {\n this.#frontmatter = null\n return undefined\n }\n\n this.#frontmatter = yamlLoad(yamlLines.join('\\n')) as Record<string, unknown>\n return this.#frontmatter\n }\n\n // ── Structural index queries ──────────────────────────────────────────────\n\n /**\n * Returns all headings in document order, optionally filtered by depth.\n *\n * @remarks\n * Uses the cached structural index — no content is fetched from the {@link @nhtio/adk!SpoolReader}.\n *\n * @param depth - When provided, only headings at this ATX depth (1–6) are returned.\n */\n async md_headings(depth?: 1 | 2 | 3 | 4 | 5 | 6): Promise<MarkdownHeadingEntry[]> {\n const index = await this.#resolveIndex()\n if (depth === undefined) return index.headings.slice()\n return index.headings.filter((h) => h.depth === depth)\n }\n\n /**\n * Returns all fenced code block entries, optionally filtered by language identifier.\n *\n * @remarks\n * Returns line-range metadata only — no content is fetched. Use `cat(entry.startLine + 1,\n * entry.endLine)` to retrieve the code body (excluding fence lines).\n *\n * @param lang - When provided, only blocks with this exact lang identifier are returned.\n * Pass an empty string to match blocks with no lang identifier.\n */\n async md_code_blocks(lang?: string): Promise<MarkdownCodeEntry[]> {\n const index = await this.#resolveIndex()\n if (lang === undefined) return index.codeBlocks.slice()\n const target = lang === '' ? null : lang\n return index.codeBlocks.filter((b) => b.lang === target)\n }\n\n /**\n * Returns document sections derived from the structural index.\n *\n * @remarks\n * Returns only line-range metadata — body content is never fetched. To retrieve the body of a\n * section, call `cat(section.bodyStartLine, section.bodyEndLine + 1)`.\n *\n * When `depth` is provided, only sections introduced by a heading at that depth are returned;\n * deeper headings become part of the body.\n *\n * @param depth - When provided, only sections at this ATX depth (1–6) are returned.\n */\n async md_sections(depth?: 1 | 2 | 3 | 4 | 5 | 6): Promise<MarkdownSection[]> {\n const index = await this.#resolveIndex()\n const headings =\n depth !== undefined ? index.headings.filter((h) => h.depth === depth) : index.headings\n return headings.map((h) => ({\n depth: h.depth,\n heading: h.text,\n headingLine: h.startLine,\n bodyStartLine: h.startLine + 1,\n bodyEndLine: h.endLine,\n }))\n }\n\n // ── Inline queries (bounded) ──────────────────────────────────────────────\n\n /**\n * Returns the full MDAST Root for the specified line range.\n *\n * @remarks\n * Without a range, reads the full document — for large documents, use\n * {@link SpooledMarkdownArtifact.md_sections} to locate sections and pass\n * bounded line ranges here.\n *\n * @param startLine - 0-based start line (inclusive). Defaults to `0`.\n * @param endLine - 0-based end line (exclusive). Defaults to `lineCount()`.\n */\n async md_ast(startLine?: number, endLine?: number): Promise<Root> {\n const lines = await this.cat(startLine, endLine)\n return processor().parse(lines.join('\\n')) as Root\n }\n\n /**\n * Returns all inline and reference links in the specified line range.\n *\n * @param startLine - 0-based start line (inclusive). Defaults to `0`.\n * @param endLine - 0-based end line (exclusive). Defaults to `lineCount()`.\n */\n async md_links(\n startLine?: number,\n endLine?: number\n ): Promise<Array<{ text: string; url: string; title?: string }>> {\n const lines = await this.cat(startLine, endLine)\n const ast = processor().parse(lines.join('\\n'))\n const results: Array<{ text: string; url: string; title?: string }> = []\n visit(ast, 'link', (node: Link) => {\n results.push({\n text: mdastToString(node),\n url: node.url,\n title: node.title ?? undefined,\n })\n })\n return results\n }\n\n /**\n * Returns all images in the specified line range.\n *\n * @param startLine - 0-based start line (inclusive). Defaults to `0`.\n * @param endLine - 0-based end line (exclusive). Defaults to `lineCount()`.\n */\n async md_images(\n startLine?: number,\n endLine?: number\n ): Promise<Array<{ alt: string; url: string; title?: string }>> {\n const lines = await this.cat(startLine, endLine)\n const ast = processor().parse(lines.join('\\n'))\n const results: Array<{ alt: string; url: string; title?: string }> = []\n visit(ast, 'image', (node: Image) => {\n results.push({\n alt: node.alt ?? '',\n url: node.url,\n title: node.title ?? undefined,\n })\n })\n return results\n }\n\n /**\n * Returns all document text with markup stripped, for the specified line range.\n *\n * @remarks\n * Uses `mdast-util-to-string` to extract plain text from the AST — code, link text, and\n * alt text are included; markdown syntax is removed.\n *\n * @param startLine - 0-based start line (inclusive). Defaults to `0`.\n * @param endLine - 0-based end line (exclusive). Defaults to `lineCount()`.\n */\n async md_text(startLine?: number, endLine?: number): Promise<string> {\n const lines = await this.cat(startLine, endLine)\n const ast = processor().parse(lines.join('\\n'))\n return mdastToString(ast)\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
import { a as validateOrThrow } from "./exceptions-NrzIHw_R.mjs";
|
|
2
|
+
import { a as Tokenizable, o as isError, s as isInstanceOf } from "./tool_registry-DqLOyGyG.mjs";
|
|
3
|
+
import { a as E_INVALID_INITIAL_MEMORY_VALUE, l as E_INVALID_INITIAL_THOUGHT_VALUE, o as E_INVALID_INITIAL_MESSAGE_VALUE, r as E_INVALID_INITIAL_IDENTITY_VALUE } from "./runtime-CrEPIFgr.mjs";
|
|
4
|
+
import { n as Media } from "./tool_call-BKyyxGaZ.mjs";
|
|
5
|
+
import { validator } from "@nhtio/validation";
|
|
6
|
+
//#region src/lib/classes/identity.ts
|
|
7
|
+
/**
|
|
8
|
+
* Validator schema used to validate a {@link RawIdentity} before constructing an {@link Identity}.
|
|
9
|
+
*
|
|
10
|
+
* @remarks
|
|
11
|
+
* Validates both fields of {@link RawIdentity}:
|
|
12
|
+
* - `identifier` — required string or number.
|
|
13
|
+
* - `representation` — required string or {@link @nhtio/adk!Tokenizable}, via {@link @nhtio/adk!Tokenizable.schema}.
|
|
14
|
+
*
|
|
15
|
+
* Throws {@link @nhtio/adk!E_INVALID_INITIAL_IDENTITY_VALUE} (via the {@link Identity} constructor) when
|
|
16
|
+
* validation fails.
|
|
17
|
+
*/
|
|
18
|
+
var rawIdentitySchema = validator.object({
|
|
19
|
+
identifier: validator.alternatives(validator.string(), validator.number()).required(),
|
|
20
|
+
representation: Tokenizable.schema.required()
|
|
21
|
+
});
|
|
22
|
+
/**
|
|
23
|
+
* An immutable, validated participant identity attached to a {@link @nhtio/adk!Message}.
|
|
24
|
+
*
|
|
25
|
+
* @remarks
|
|
26
|
+
* Carries two distinct representations of the same participant: `identifier` is the
|
|
27
|
+
* system-facing key (e.g. a database ID) used to correlate messages programmatically;
|
|
28
|
+
* `representation` is what the model sees when it needs to distinguish between participants
|
|
29
|
+
* sharing the same role. The `representation` is always a {@link @nhtio/adk!Tokenizable} so token cost
|
|
30
|
+
* can be estimated inline.
|
|
31
|
+
*/
|
|
32
|
+
var Identity = class Identity {
|
|
33
|
+
/**
|
|
34
|
+
* Validator schema that accepts a {@link RawIdentity} object.
|
|
35
|
+
*
|
|
36
|
+
* @remarks
|
|
37
|
+
* Reusable fragment for any schema that needs to validate or nest an identity — for example,
|
|
38
|
+
* as a required field inside a message schema.
|
|
39
|
+
*/
|
|
40
|
+
static schema = rawIdentitySchema;
|
|
41
|
+
/**
|
|
42
|
+
* Returns `true` if `value` is an {@link Identity} instance.
|
|
43
|
+
*
|
|
44
|
+
* @remarks
|
|
45
|
+
* Uses {@link @nhtio/adk!isInstanceOf} for cross-realm safety — `instanceof` would fail for instances
|
|
46
|
+
* created in a different module copy or VM context.
|
|
47
|
+
*
|
|
48
|
+
* @param value - The value to test.
|
|
49
|
+
* @returns `true` when `value` is an {@link Identity} instance.
|
|
50
|
+
*/
|
|
51
|
+
static isIdentity(value) {
|
|
52
|
+
return isInstanceOf(value, "Identity", Identity);
|
|
53
|
+
}
|
|
54
|
+
#identifier;
|
|
55
|
+
#representation;
|
|
56
|
+
/**
|
|
57
|
+
* @param raw - The raw identity input validated against `rawIdentitySchema`.
|
|
58
|
+
* @throws {@link @nhtio/adk!E_INVALID_INITIAL_IDENTITY_VALUE} when `raw` does not satisfy the schema.
|
|
59
|
+
*/
|
|
60
|
+
constructor(raw) {
|
|
61
|
+
let resolved;
|
|
62
|
+
try {
|
|
63
|
+
resolved = validateOrThrow(rawIdentitySchema, raw, true);
|
|
64
|
+
} catch (err) {
|
|
65
|
+
throw new E_INVALID_INITIAL_IDENTITY_VALUE({ cause: isError(err) ? err : void 0 });
|
|
66
|
+
}
|
|
67
|
+
this.#identifier = resolved.identifier;
|
|
68
|
+
this.#representation = Tokenizable.isTokenizable(resolved.representation) ? resolved.representation : new Tokenizable(resolved.representation);
|
|
69
|
+
Object.defineProperties(this, {
|
|
70
|
+
identifier: {
|
|
71
|
+
get: () => this.#identifier,
|
|
72
|
+
enumerable: true,
|
|
73
|
+
configurable: false
|
|
74
|
+
},
|
|
75
|
+
representation: {
|
|
76
|
+
get: () => this.#representation,
|
|
77
|
+
enumerable: true,
|
|
78
|
+
configurable: false
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
//#endregion
|
|
84
|
+
//#region src/lib/classes/memory.ts
|
|
85
|
+
/**
|
|
86
|
+
* Validator schema used to validate a {@link RawMemory} before constructing a {@link Memory}.
|
|
87
|
+
*
|
|
88
|
+
* @remarks
|
|
89
|
+
* Validates all six fields of {@link RawMemory}:
|
|
90
|
+
* - `id` — required non-empty string.
|
|
91
|
+
* - `content` — required string or {@link @nhtio/adk!Tokenizable}, via {@link @nhtio/adk!Tokenizable.schema}.
|
|
92
|
+
* - `confidence` — required number in `[0, 1]`.
|
|
93
|
+
* - `importance` — required number in `[0, 1]`.
|
|
94
|
+
* - `createdAt` / `updatedAt` — required datetime-parseable values, normalised to `DateTime`.
|
|
95
|
+
*
|
|
96
|
+
* Throws {@link @nhtio/adk!E_INVALID_INITIAL_MEMORY_VALUE} (via the {@link Memory} constructor) when
|
|
97
|
+
* validation fails.
|
|
98
|
+
*/
|
|
99
|
+
var rawMemorySchema = validator.object({
|
|
100
|
+
id: validator.string().required(),
|
|
101
|
+
content: Tokenizable.schema.required(),
|
|
102
|
+
confidence: validator.number().min(0).max(1).required(),
|
|
103
|
+
importance: validator.number().min(0).max(1).required(),
|
|
104
|
+
createdAt: validator.datetime().required(),
|
|
105
|
+
updatedAt: validator.datetime().required()
|
|
106
|
+
});
|
|
107
|
+
/**
|
|
108
|
+
* An immutable, validated memory entry held by the agent.
|
|
109
|
+
*
|
|
110
|
+
* @remarks
|
|
111
|
+
* Constructed from a {@link RawMemory} via `rawMemorySchema`. All temporal fields are
|
|
112
|
+
* normalised to Luxon `DateTime` instances at construction time. The `content` field is
|
|
113
|
+
* always a {@link @nhtio/adk!Tokenizable} so callers can estimate token cost without an additional
|
|
114
|
+
* wrapping step.
|
|
115
|
+
*/
|
|
116
|
+
var Memory = class Memory {
|
|
117
|
+
/**
|
|
118
|
+
* Validator schema that accepts a {@link RawMemory} object.
|
|
119
|
+
*
|
|
120
|
+
* @remarks
|
|
121
|
+
* Reusable fragment for any schema that needs to validate or nest a memory entry — for
|
|
122
|
+
* example, a collection schema that holds an array of memories.
|
|
123
|
+
*/
|
|
124
|
+
static schema = rawMemorySchema;
|
|
125
|
+
/**
|
|
126
|
+
* Returns `true` if `value` is a {@link Memory} instance.
|
|
127
|
+
*
|
|
128
|
+
* @remarks
|
|
129
|
+
* Uses {@link @nhtio/adk!isInstanceOf} for cross-realm safety — `instanceof` would fail for instances
|
|
130
|
+
* created in a different module copy or VM context.
|
|
131
|
+
*
|
|
132
|
+
* @param value - The value to test.
|
|
133
|
+
* @returns `true` when `value` is a {@link Memory} instance.
|
|
134
|
+
*/
|
|
135
|
+
static isMemory(value) {
|
|
136
|
+
return isInstanceOf(value, "Memory", Memory);
|
|
137
|
+
}
|
|
138
|
+
#id;
|
|
139
|
+
#content;
|
|
140
|
+
#confidence;
|
|
141
|
+
#importance;
|
|
142
|
+
#createdAt;
|
|
143
|
+
#updatedAt;
|
|
144
|
+
/**
|
|
145
|
+
* @param raw - The raw memory input validated against `rawMemorySchema`.
|
|
146
|
+
* @throws {@link @nhtio/adk!E_INVALID_INITIAL_MEMORY_VALUE} when `raw` does not satisfy the schema.
|
|
147
|
+
*/
|
|
148
|
+
constructor(raw) {
|
|
149
|
+
let resolved;
|
|
150
|
+
try {
|
|
151
|
+
resolved = validateOrThrow(rawMemorySchema, raw, true);
|
|
152
|
+
} catch (err) {
|
|
153
|
+
throw new E_INVALID_INITIAL_MEMORY_VALUE({ cause: isError(err) ? err : void 0 });
|
|
154
|
+
}
|
|
155
|
+
this.#id = resolved.id;
|
|
156
|
+
this.#content = Tokenizable.isTokenizable(resolved.content) ? resolved.content : new Tokenizable(resolved.content);
|
|
157
|
+
this.#confidence = resolved.confidence;
|
|
158
|
+
this.#importance = resolved.importance;
|
|
159
|
+
this.#createdAt = resolved.createdAt;
|
|
160
|
+
this.#updatedAt = resolved.updatedAt;
|
|
161
|
+
Object.defineProperties(this, {
|
|
162
|
+
id: {
|
|
163
|
+
get: () => this.#id,
|
|
164
|
+
enumerable: true,
|
|
165
|
+
configurable: false
|
|
166
|
+
},
|
|
167
|
+
content: {
|
|
168
|
+
get: () => this.#content,
|
|
169
|
+
enumerable: true,
|
|
170
|
+
configurable: false
|
|
171
|
+
},
|
|
172
|
+
confidence: {
|
|
173
|
+
get: () => this.#confidence,
|
|
174
|
+
enumerable: true,
|
|
175
|
+
configurable: false
|
|
176
|
+
},
|
|
177
|
+
importance: {
|
|
178
|
+
get: () => this.#importance,
|
|
179
|
+
enumerable: true,
|
|
180
|
+
configurable: false
|
|
181
|
+
},
|
|
182
|
+
createdAt: {
|
|
183
|
+
get: () => this.#createdAt,
|
|
184
|
+
enumerable: true,
|
|
185
|
+
configurable: false
|
|
186
|
+
},
|
|
187
|
+
updatedAt: {
|
|
188
|
+
get: () => this.#updatedAt,
|
|
189
|
+
enumerable: true,
|
|
190
|
+
configurable: false
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
//#endregion
|
|
196
|
+
//#region src/lib/classes/message.ts
|
|
197
|
+
/**
|
|
198
|
+
* Validator schema used to validate a {@link RawMessage} before constructing a {@link Message}.
|
|
199
|
+
*
|
|
200
|
+
* @remarks
|
|
201
|
+
* Validates all fields of {@link RawMessage}:
|
|
202
|
+
* - `id` — required non-empty string.
|
|
203
|
+
* - `role` — required; must be `'user'` or `'assistant'`.
|
|
204
|
+
* - `content` — optional string or {@link @nhtio/adk!Tokenizable}, via {@link @nhtio/adk!Tokenizable.schema}.
|
|
205
|
+
* - `attachments` — optional array of {@link @nhtio/adk!Media} instances. Defaults to `[]`.
|
|
206
|
+
* - At least one of `content` or `attachments` must be present and non-empty; a message with
|
|
207
|
+
* neither is invalid.
|
|
208
|
+
* - `identity` — required string, {@link @nhtio/adk!RawIdentity}, or {@link @nhtio/adk!Identity}; a plain string is
|
|
209
|
+
* mapped to both `identifier` and `representation` automatically.
|
|
210
|
+
* - `createdAt` / `updatedAt` — required datetime-parseable values, normalised to `DateTime`.
|
|
211
|
+
*
|
|
212
|
+
* Throws {@link @nhtio/adk!E_INVALID_INITIAL_MESSAGE_VALUE} (via the {@link Message} constructor) when
|
|
213
|
+
* validation fails.
|
|
214
|
+
*/
|
|
215
|
+
var rawMessageSchema = validator.object({
|
|
216
|
+
id: validator.string().required(),
|
|
217
|
+
role: validator.string().valid("user", "assistant").required(),
|
|
218
|
+
content: Tokenizable.schema.optional(),
|
|
219
|
+
attachments: validator.array().items(validator.any().custom((value, helpers) => {
|
|
220
|
+
if (Media.isMedia(value)) return value;
|
|
221
|
+
return helpers.error("any.invalid");
|
|
222
|
+
})).default([]),
|
|
223
|
+
identity: validator.alternatives(validator.string(), Identity.schema).default(validator.ref("role")),
|
|
224
|
+
createdAt: validator.datetime().required(),
|
|
225
|
+
updatedAt: validator.datetime().required()
|
|
226
|
+
}).custom((value, helpers) => {
|
|
227
|
+
const resolved = value;
|
|
228
|
+
const hasContent = resolved.content !== void 0 && resolved.content !== null;
|
|
229
|
+
const hasAttachments = Array.isArray(resolved.attachments) && resolved.attachments.length > 0;
|
|
230
|
+
if (!hasContent && !hasAttachments) return helpers.error("any.invalid");
|
|
231
|
+
return resolved;
|
|
232
|
+
});
|
|
233
|
+
/**
|
|
234
|
+
* An immutable, validated conversation message from a human participant or the model.
|
|
235
|
+
*
|
|
236
|
+
* @remarks
|
|
237
|
+
* Covers only `user` and `assistant` roles — system instructions, developer directives, and
|
|
238
|
+
* tool results are not represented here. Constructed from a {@link RawMessage} via
|
|
239
|
+
* `rawMessageSchema`. Temporal fields are normalised to Luxon `DateTime` instances at
|
|
240
|
+
* construction time. Both `content` and `identity.representation` are {@link @nhtio/adk!Tokenizable} so
|
|
241
|
+
* token cost can be estimated inline.
|
|
242
|
+
*
|
|
243
|
+
* A message may carry `content` (text), `attachments` (media), or both. The cross-field rule
|
|
244
|
+
* on `rawMessageSchema` enforces that at least one is present. Downstream code that reaches
|
|
245
|
+
* for `message.content` must handle the attachments-only case where `content` is `undefined`.
|
|
246
|
+
*/
|
|
247
|
+
var Message = class Message {
|
|
248
|
+
/**
|
|
249
|
+
* Validator schema that accepts a {@link RawMessage} object.
|
|
250
|
+
*
|
|
251
|
+
* @remarks
|
|
252
|
+
* Reusable fragment for any schema that needs to validate or nest a message entry — for
|
|
253
|
+
* example, a collection schema that holds an array of messages.
|
|
254
|
+
*/
|
|
255
|
+
static schema = rawMessageSchema;
|
|
256
|
+
/**
|
|
257
|
+
* Returns `true` if `value` is a {@link Message} instance.
|
|
258
|
+
*
|
|
259
|
+
* @remarks
|
|
260
|
+
* Uses {@link @nhtio/adk!isInstanceOf} for cross-realm safety — `instanceof` would fail for instances
|
|
261
|
+
* created in a different module copy or VM context.
|
|
262
|
+
*
|
|
263
|
+
* @param value - The value to test.
|
|
264
|
+
* @returns `true` when `value` is a {@link Message} instance.
|
|
265
|
+
*/
|
|
266
|
+
static isMessage(value) {
|
|
267
|
+
return isInstanceOf(value, "Message", Message);
|
|
268
|
+
}
|
|
269
|
+
#id;
|
|
270
|
+
#role;
|
|
271
|
+
#content;
|
|
272
|
+
#attachments;
|
|
273
|
+
#identity;
|
|
274
|
+
#createdAt;
|
|
275
|
+
#updatedAt;
|
|
276
|
+
/**
|
|
277
|
+
* @param raw - The raw message input validated against `rawMessageSchema`.
|
|
278
|
+
* @throws {@link @nhtio/adk!E_INVALID_INITIAL_MESSAGE_VALUE} when `raw` does not satisfy the schema —
|
|
279
|
+
* including the cross-field rule that at least one of `content` or `attachments` must be
|
|
280
|
+
* present and non-empty.
|
|
281
|
+
*/
|
|
282
|
+
constructor(raw) {
|
|
283
|
+
let resolved;
|
|
284
|
+
try {
|
|
285
|
+
resolved = validateOrThrow(rawMessageSchema, raw, true);
|
|
286
|
+
} catch (err) {
|
|
287
|
+
throw new E_INVALID_INITIAL_MESSAGE_VALUE({ cause: isError(err) ? err : void 0 });
|
|
288
|
+
}
|
|
289
|
+
this.#id = resolved.id;
|
|
290
|
+
this.#role = resolved.role;
|
|
291
|
+
this.#content = resolved.content === void 0 || resolved.content === null ? void 0 : Tokenizable.isTokenizable(resolved.content) ? resolved.content : new Tokenizable(resolved.content);
|
|
292
|
+
this.#attachments = Object.freeze([...resolved.attachments ?? []]);
|
|
293
|
+
const rawIdentity = resolved.identity;
|
|
294
|
+
this.#identity = Identity.isIdentity(rawIdentity) ? rawIdentity : typeof rawIdentity === "string" ? new Identity({
|
|
295
|
+
identifier: rawIdentity,
|
|
296
|
+
representation: rawIdentity
|
|
297
|
+
}) : new Identity(rawIdentity);
|
|
298
|
+
this.#createdAt = resolved.createdAt;
|
|
299
|
+
this.#updatedAt = resolved.updatedAt;
|
|
300
|
+
Object.defineProperties(this, {
|
|
301
|
+
id: {
|
|
302
|
+
get: () => this.#id,
|
|
303
|
+
enumerable: true,
|
|
304
|
+
configurable: false
|
|
305
|
+
},
|
|
306
|
+
role: {
|
|
307
|
+
get: () => this.#role,
|
|
308
|
+
enumerable: true,
|
|
309
|
+
configurable: false
|
|
310
|
+
},
|
|
311
|
+
content: {
|
|
312
|
+
get: () => this.#content,
|
|
313
|
+
enumerable: true,
|
|
314
|
+
configurable: false
|
|
315
|
+
},
|
|
316
|
+
attachments: {
|
|
317
|
+
get: () => this.#attachments,
|
|
318
|
+
enumerable: true,
|
|
319
|
+
configurable: false
|
|
320
|
+
},
|
|
321
|
+
identity: {
|
|
322
|
+
get: () => this.#identity,
|
|
323
|
+
enumerable: true,
|
|
324
|
+
configurable: false
|
|
325
|
+
},
|
|
326
|
+
createdAt: {
|
|
327
|
+
get: () => this.#createdAt,
|
|
328
|
+
enumerable: true,
|
|
329
|
+
configurable: false
|
|
330
|
+
},
|
|
331
|
+
updatedAt: {
|
|
332
|
+
get: () => this.#updatedAt,
|
|
333
|
+
enumerable: true,
|
|
334
|
+
configurable: false
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
//#endregion
|
|
340
|
+
//#region src/lib/classes/thought.ts
|
|
341
|
+
/**
|
|
342
|
+
* Validator schema used to validate a {@link RawThought} before constructing a {@link Thought}.
|
|
343
|
+
*
|
|
344
|
+
* @remarks
|
|
345
|
+
* Validates all fields of {@link RawThought}:
|
|
346
|
+
* - `id` — required non-empty string.
|
|
347
|
+
* - `content` — required string or {@link @nhtio/adk!Tokenizable}, via {@link @nhtio/adk!Tokenizable.schema}.
|
|
348
|
+
* - `identity` — optional string, {@link @nhtio/adk!RawIdentity}, or {@link @nhtio/adk!Identity}; defaults to
|
|
349
|
+
* `'assistant'` when omitted.
|
|
350
|
+
* - `createdAt` / `updatedAt` — required datetime-parseable values, normalised to `DateTime`.
|
|
351
|
+
*
|
|
352
|
+
* Throws {@link @nhtio/adk!E_INVALID_INITIAL_THOUGHT_VALUE} (via the {@link Thought} constructor) when
|
|
353
|
+
* validation fails.
|
|
354
|
+
*/
|
|
355
|
+
var rawThoughtSchema = validator.object({
|
|
356
|
+
id: validator.string().required(),
|
|
357
|
+
content: Tokenizable.schema.required(),
|
|
358
|
+
identity: validator.alternatives(validator.string(), Identity.schema).default("assistant"),
|
|
359
|
+
payload: validator.any().optional(),
|
|
360
|
+
replayCompatibility: validator.string().min(1).optional(),
|
|
361
|
+
createdAt: validator.datetime().required(),
|
|
362
|
+
updatedAt: validator.datetime().required()
|
|
363
|
+
}).custom((value, helpers) => {
|
|
364
|
+
const v = value;
|
|
365
|
+
if (v.payload !== void 0 && (v.replayCompatibility === void 0 || v.replayCompatibility === null)) return helpers.error("any.invalid");
|
|
366
|
+
return value;
|
|
367
|
+
});
|
|
368
|
+
/**
|
|
369
|
+
* An immutable, validated internal reasoning trace produced by an agent.
|
|
370
|
+
*
|
|
371
|
+
* @remarks
|
|
372
|
+
* Represents an agent's internal thinking — distinct from {@link @nhtio/adk!Message} (which is part of
|
|
373
|
+
* the visible conversation) and never shown to end users directly. Carries an `identity` so
|
|
374
|
+
* reasoning traces can be attributed to a specific agent in multi-agent conversations.
|
|
375
|
+
* Constructed from a {@link RawThought} via `rawThoughtSchema`. The `content` field is always
|
|
376
|
+
* a {@link @nhtio/adk!Tokenizable} so token cost can be estimated inline.
|
|
377
|
+
*/
|
|
378
|
+
var Thought = class Thought {
|
|
379
|
+
/**
|
|
380
|
+
* Validator schema that accepts a {@link RawThought} object.
|
|
381
|
+
*
|
|
382
|
+
* @remarks
|
|
383
|
+
* Reusable fragment for any schema that needs to validate or nest a thought entry.
|
|
384
|
+
*/
|
|
385
|
+
static schema = rawThoughtSchema;
|
|
386
|
+
/**
|
|
387
|
+
* Returns `true` if `value` is a {@link Thought} instance.
|
|
388
|
+
*
|
|
389
|
+
* @remarks
|
|
390
|
+
* Uses {@link @nhtio/adk!isInstanceOf} for cross-realm safety — `instanceof` would fail for instances
|
|
391
|
+
* created in a different module copy or VM context.
|
|
392
|
+
*
|
|
393
|
+
* @param value - The value to test.
|
|
394
|
+
* @returns `true` when `value` is a {@link Thought} instance.
|
|
395
|
+
*/
|
|
396
|
+
static isThought(value) {
|
|
397
|
+
return isInstanceOf(value, "Thought", Thought);
|
|
398
|
+
}
|
|
399
|
+
#id;
|
|
400
|
+
#content;
|
|
401
|
+
#identity;
|
|
402
|
+
#payload;
|
|
403
|
+
#replayCompatibility;
|
|
404
|
+
#createdAt;
|
|
405
|
+
#updatedAt;
|
|
406
|
+
/**
|
|
407
|
+
* @param raw - The raw thought input validated against `rawThoughtSchema`.
|
|
408
|
+
* @throws {@link @nhtio/adk!E_INVALID_INITIAL_THOUGHT_VALUE} when `raw` does not satisfy the schema.
|
|
409
|
+
*/
|
|
410
|
+
constructor(raw) {
|
|
411
|
+
let resolved;
|
|
412
|
+
try {
|
|
413
|
+
resolved = validateOrThrow(rawThoughtSchema, raw, true);
|
|
414
|
+
} catch (err) {
|
|
415
|
+
throw new E_INVALID_INITIAL_THOUGHT_VALUE({ cause: isError(err) ? err : void 0 });
|
|
416
|
+
}
|
|
417
|
+
this.#id = resolved.id;
|
|
418
|
+
this.#content = Tokenizable.isTokenizable(resolved.content) ? resolved.content : new Tokenizable(resolved.content);
|
|
419
|
+
const rawIdentity = resolved.identity;
|
|
420
|
+
this.#identity = Identity.isIdentity(rawIdentity) ? rawIdentity : typeof rawIdentity === "string" ? new Identity({
|
|
421
|
+
identifier: rawIdentity,
|
|
422
|
+
representation: rawIdentity
|
|
423
|
+
}) : new Identity(rawIdentity);
|
|
424
|
+
this.#payload = resolved.payload;
|
|
425
|
+
this.#replayCompatibility = resolved.replayCompatibility;
|
|
426
|
+
this.#createdAt = resolved.createdAt;
|
|
427
|
+
this.#updatedAt = resolved.updatedAt;
|
|
428
|
+
Object.defineProperties(this, {
|
|
429
|
+
id: {
|
|
430
|
+
get: () => this.#id,
|
|
431
|
+
enumerable: true,
|
|
432
|
+
configurable: false
|
|
433
|
+
},
|
|
434
|
+
content: {
|
|
435
|
+
get: () => this.#content,
|
|
436
|
+
enumerable: true,
|
|
437
|
+
configurable: false
|
|
438
|
+
},
|
|
439
|
+
identity: {
|
|
440
|
+
get: () => this.#identity,
|
|
441
|
+
enumerable: true,
|
|
442
|
+
configurable: false
|
|
443
|
+
},
|
|
444
|
+
payload: {
|
|
445
|
+
get: () => this.#payload,
|
|
446
|
+
enumerable: true,
|
|
447
|
+
configurable: false
|
|
448
|
+
},
|
|
449
|
+
replayCompatibility: {
|
|
450
|
+
get: () => this.#replayCompatibility,
|
|
451
|
+
enumerable: true,
|
|
452
|
+
configurable: false
|
|
453
|
+
},
|
|
454
|
+
createdAt: {
|
|
455
|
+
get: () => this.#createdAt,
|
|
456
|
+
enumerable: true,
|
|
457
|
+
configurable: false
|
|
458
|
+
},
|
|
459
|
+
updatedAt: {
|
|
460
|
+
get: () => this.#updatedAt,
|
|
461
|
+
enumerable: true,
|
|
462
|
+
configurable: false
|
|
463
|
+
}
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
//#endregion
|
|
468
|
+
export { Identity as i, Message as n, Memory as r, Thought as t };
|
|
469
|
+
|
|
470
|
+
//# sourceMappingURL=thought-CDb457b4.mjs.map
|