dna-sdk 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/prompts.js CHANGED
@@ -24,6 +24,7 @@
24
24
  * is `await`ed in TS but not in Python).
25
25
  */
26
26
  import { quickInstance } from "./bootstrap.js";
27
+ import { anchorScopesRoot } from "./package-scope.js";
27
28
  /** Lazy, cached view `agent name -> composed prompt` over one scope. */
28
29
  export class PromptLibrary {
29
30
  mi;
@@ -65,12 +66,26 @@ export class PromptLibrary {
65
66
  /**
66
67
  * Compose the prompts of `scope` behind a {@link PromptLibrary}.
67
68
  *
68
- * `baseDir` follows the {@link quickInstance} convention the directory that
69
- * holds `<scope>/` (the `.dna` scopes root). Omitted → the `DNA_BASE_DIR` env
70
- * var, then `.dna` in the cwd.
69
+ * Precedence for the scopes-root (first one set wins):
70
+ *
71
+ * `opts.baseDir` > `$DNA_BASE_DIR` > `opts.anchor` (package data) > `.dna`
72
+ *
73
+ * The legacy positional-string form (`loadPrompts(scope, "/path/.dna")`) is
74
+ * still accepted for back-compat and is treated as `baseDir`.
71
75
  */
72
- export async function loadPrompts(scope, baseDir) {
73
- const resolved = baseDir ?? process.env.DNA_BASE_DIR ?? ".dna";
74
- const mi = await quickInstance(scope, resolved);
76
+ export async function loadPrompts(scope, opts) {
77
+ const o = typeof opts === "string" ? { baseDir: opts } : opts ?? {};
78
+ const mi = await quickInstance(scope, resolveScopeBaseDir(o));
75
79
  return new PromptLibrary(mi);
76
80
  }
81
+ /** Pick the `.dna` scopes-root by the documented precedence. */
82
+ function resolveScopeBaseDir(o) {
83
+ if (o.baseDir !== undefined)
84
+ return o.baseDir;
85
+ const env = process.env.DNA_BASE_DIR;
86
+ if (env)
87
+ return env;
88
+ if (o.anchor !== undefined)
89
+ return anchorScopesRoot(o.anchor);
90
+ return ".dna";
91
+ }
@@ -0,0 +1,41 @@
1
+ import { ToolNotFound } from "./kernel/errors.js";
2
+ import type { ManifestInstance } from "./kernel/instance.js";
3
+ export { ToolNotFound };
4
+ /**
5
+ * The agent-facing surface of a Tool — exactly what a tool-calling model is
6
+ * shown to decide whether, and how, to call it.
7
+ */
8
+ export interface ToolSurface {
9
+ /** Natural-language description (`metadata.description`) — the text the
10
+ * model reads. */
11
+ readonly description: string;
12
+ /** JSON Schema of the arguments (`spec.input_schema`) — what the model
13
+ * fills in. Empty `{}` when the tool takes no args. */
14
+ readonly parameters: Record<string, unknown>;
15
+ }
16
+ /** Lazy, cached view `tool name -> ToolSurface` over one scope. */
17
+ export declare class ToolLibrary {
18
+ /** The underlying ManifestInstance (drop down for the full surface). */
19
+ readonly mi: ManifestInstance;
20
+ private readonly cache;
21
+ constructor(
22
+ /** The underlying ManifestInstance (drop down for the full surface). */
23
+ mi: ManifestInstance);
24
+ /**
25
+ * Project `name`'s agent-facing surface (cached). Throws {@link ToolNotFound}
26
+ * on a miss.
27
+ */
28
+ get(name: string): ToolSurface;
29
+ /** True when `name` is a Tool document in the scope (no projection). */
30
+ has(name: string): boolean;
31
+ /** Names of every Tool document in the scope, sorted. */
32
+ names(): string[];
33
+ }
34
+ /**
35
+ * Load the Tool surfaces of `scope` behind a {@link ToolLibrary}.
36
+ *
37
+ * `baseDir` follows the {@link quickInstance} convention — the directory that
38
+ * holds `<scope>/` (the `.dna` scopes root). Omitted → the `DNA_BASE_DIR` env
39
+ * var, then `.dna` in the cwd.
40
+ */
41
+ export declare function loadTools(scope: string, baseDir?: string): Promise<ToolLibrary>;
package/dist/tools.js ADDED
@@ -0,0 +1,88 @@
1
+ /**
2
+ * `loadTools` — the agent-facing tool surface, as data (TS twin of python
3
+ * `dna.load_tools`).
4
+ *
5
+ * The DNA already governs persona, instruction and guardrails declaratively.
6
+ * A **Tool** (record-plane Kind, `helix/kinds/tool.kind.yaml`) moves the last
7
+ * hard-coded piece into the same plane: the `description` the model reads to
8
+ * decide whether to call a tool, and the JSON Schema of its `parameters`.
9
+ * `loadTools` is the consumer one-liner — the twin of `loadPrompts`:
10
+ *
11
+ * ```ts
12
+ * import { loadTools } from "@ruinosus/dna";
13
+ *
14
+ * const tools = await loadTools("open-swe");
15
+ * const surface = tools.get("github-search"); // or throws ToolNotFound
16
+ * surface.description; // the text the model reads
17
+ * surface.parameters; // the args JSON Schema
18
+ * ```
19
+ *
20
+ * Because a Tool is ONE declarative document, the SAME surface is served to a
21
+ * Python backend (a `@tool` function's `description=`) and this TypeScript
22
+ * frontend (CopilotKit `useCopilotAction`) from one source of truth — the
23
+ * first place the Py↔TS descriptor parity pays off in a real consumer (see
24
+ * `examples/tools_as_data`).
25
+ *
26
+ * TS/Py asymmetry: `loadTools` is async (booting the kernel is async, exactly
27
+ * like `loadPrompts`), but `get(name)` is SYNC — reading a record document
28
+ * needs no async work (unlike `loadPrompts.get`, which awaits composition).
29
+ * A missing tool throws {@link ToolNotFound} (never an empty surface).
30
+ * Overlay-aware: a tenant overlay that overrides a tool's
31
+ * `metadata.description` / `spec.input_schema` is reflected here.
32
+ */
33
+ import { quickInstance } from "./bootstrap.js";
34
+ import { ToolNotFound } from "./kernel/errors.js";
35
+ export { ToolNotFound };
36
+ /** Lazy, cached view `tool name -> ToolSurface` over one scope. */
37
+ export class ToolLibrary {
38
+ mi;
39
+ cache = new Map();
40
+ constructor(
41
+ /** The underlying ManifestInstance (drop down for the full surface). */
42
+ mi) {
43
+ this.mi = mi;
44
+ }
45
+ /**
46
+ * Project `name`'s agent-facing surface (cached). Throws {@link ToolNotFound}
47
+ * on a miss.
48
+ */
49
+ get(name) {
50
+ const cached = this.cache.get(name);
51
+ if (cached !== undefined)
52
+ return cached;
53
+ const doc = this.mi._one("Tool", name);
54
+ if (doc === null) {
55
+ throw new ToolNotFound(name, this.mi.scope ?? null, this.names());
56
+ }
57
+ const meta = doc.metadata;
58
+ const spec = doc.spec;
59
+ const description = typeof meta.description === "string" ? meta.description : "";
60
+ const rawParams = spec.input_schema;
61
+ const parameters = rawParams && typeof rawParams === "object" && !Array.isArray(rawParams)
62
+ ? { ...rawParams }
63
+ : {};
64
+ const surface = { description, parameters };
65
+ this.cache.set(name, surface);
66
+ return surface;
67
+ }
68
+ /** True when `name` is a Tool document in the scope (no projection). */
69
+ has(name) {
70
+ return this.names().includes(name);
71
+ }
72
+ /** Names of every Tool document in the scope, sorted. */
73
+ names() {
74
+ return this.mi._all("Tool").map((d) => d.name).sort();
75
+ }
76
+ }
77
+ /**
78
+ * Load the Tool surfaces of `scope` behind a {@link ToolLibrary}.
79
+ *
80
+ * `baseDir` follows the {@link quickInstance} convention — the directory that
81
+ * holds `<scope>/` (the `.dna` scopes root). Omitted → the `DNA_BASE_DIR` env
82
+ * var, then `.dna` in the cwd.
83
+ */
84
+ export async function loadTools(scope, baseDir) {
85
+ const resolved = baseDir ?? process.env.DNA_BASE_DIR ?? ".dna";
86
+ const mi = await quickInstance(scope, resolved);
87
+ return new ToolLibrary(mi);
88
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dna-sdk",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "DNA — Domain Notation of Anything (TypeScript SDK)",
5
5
  "type": "module",
6
6
  "license": "MIT",