dna-sdk 0.7.0 → 0.8.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/emit/bedrock.d.ts +47 -0
- package/dist/emit/bedrock.js +169 -0
- package/dist/emit/index.js +5 -3
- package/dist/extensions/research.js +8 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DNA → **Amazon Bedrock Agent** emitter (TS twin of python
|
|
3
|
+
* `dna.emit.bedrock`). Materializes an {@link EmitContext} into an AWS
|
|
4
|
+
* **CloudFormation** template that declares an `AWS::Bedrock::Agent` resource —
|
|
5
|
+
* the managed, declarative Bedrock Agents service. The SECOND runtime the SAME
|
|
6
|
+
* DNA source emits to (the first is Microsoft agent-framework): the portability
|
|
7
|
+
* proof — author once, emit per runtime.
|
|
8
|
+
*
|
|
9
|
+
* Why Bedrock **Agents** (not Strands / AgentCore): only Bedrock Agents has a
|
|
10
|
+
* published *declarative* schema (`Instruction`, `FoundationModel`,
|
|
11
|
+
* `ActionGroups` with a `FunctionSchema`) that maps field-for-field from a DNA
|
|
12
|
+
* agent. Emitting a CloudFormation template gives a lintable, deployable artifact
|
|
13
|
+
* that needs no AWS credential to produce or validate structurally.
|
|
14
|
+
*
|
|
15
|
+
* The de-para (DNA field → CloudFormation `AWS::Bedrock::Agent` field):
|
|
16
|
+
* metadata.name -> Resources.<Camel>Agent.Properties.AgentName
|
|
17
|
+
* metadata.description -> Properties.Description (when present)
|
|
18
|
+
* Soul + guardrails + instruction -> Properties.Instruction (flat, BYTE-EQUAL)
|
|
19
|
+
* spec.model (or Genome default_llm)-> Properties.FoundationModel (provider token stripped)
|
|
20
|
+
* spec.tools[] (Tool Kind surfaces) -> Properties.ActionGroups[0].FunctionSchema.Functions[]
|
|
21
|
+
*
|
|
22
|
+
* `toTemplate` is the PURE de-para and is parity-critical: it must build the SAME
|
|
23
|
+
* object the Python `to_template` builds from the same context.
|
|
24
|
+
*/
|
|
25
|
+
import type { EmitContext, EmitResult, EmitterPort } from "./index.js";
|
|
26
|
+
/** `concierge-grounded` → `ConciergeGrounded` (a valid CFN logical id). */
|
|
27
|
+
export declare function camel(name: string): string;
|
|
28
|
+
/** Project a DNA model coordinate → a Bedrock `FoundationModel` id. Bedrock
|
|
29
|
+
* encodes the provider inside the id (`anthropic.claude-v2`), so a DNA
|
|
30
|
+
* `prov:model` / `prov/model` provider token is dropped; a bare coordinate
|
|
31
|
+
* passes through unchanged. */
|
|
32
|
+
export declare function bedrockModelId(model: string | null): string | null;
|
|
33
|
+
/** Project a Tool's input JSON Schema → Bedrock `Function.Parameters`
|
|
34
|
+
* (`{name: {Type, Description, Required}}`). Returns the map + whether any type
|
|
35
|
+
* was coerced (for the loss report). */
|
|
36
|
+
export declare function emitParameters(inputSchema: Record<string, unknown>): {
|
|
37
|
+
params: Record<string, unknown>;
|
|
38
|
+
coerced: boolean;
|
|
39
|
+
};
|
|
40
|
+
export declare class BedrockEmitter implements EmitterPort {
|
|
41
|
+
readonly target = "bedrock";
|
|
42
|
+
readonly fileExtension = "bedrock.json";
|
|
43
|
+
/** The PURE de-para: {@link EmitContext} → the CloudFormation object. Field
|
|
44
|
+
* order is intentional and preserved by JSON.stringify (insertion order). */
|
|
45
|
+
toTemplate(ctx: EmitContext): Record<string, unknown>;
|
|
46
|
+
emit(ctx: EmitContext): EmitResult;
|
|
47
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/** Bedrock `ParameterDetail.Type` allowed values. A JSON-Schema type outside
|
|
2
|
+
* this set (notably `object`) is coerced to `string` (the depth loss). */
|
|
3
|
+
const BEDROCK_PARAM_TYPES = new Set(["string", "number", "integer", "boolean", "array"]);
|
|
4
|
+
/** CloudFormation template format version — the stable, only value. */
|
|
5
|
+
const CFN_VERSION = "2010-09-09";
|
|
6
|
+
/** DNA provider tokens (the `prov:model` / `prov/model` prefixes DNA authors
|
|
7
|
+
* use). Stripped to expose the bare model id. Bedrock-native provider prefixes
|
|
8
|
+
* (anthropic./amazon./…) use a DOT and are NOT here, so a real Bedrock id (incl.
|
|
9
|
+
* a `:0` version suffix) passes through. */
|
|
10
|
+
const DNA_PROVIDER_TOKENS = new Set([
|
|
11
|
+
"azure", "azureopenai", "azure_openai", "openai", "foundry", "azureaifoundry",
|
|
12
|
+
"vertex", "google", "gemini",
|
|
13
|
+
]);
|
|
14
|
+
/** `concierge-grounded` → `ConciergeGrounded` (a valid CFN logical id). */
|
|
15
|
+
export function camel(name) {
|
|
16
|
+
return String(name)
|
|
17
|
+
.replace(/_/g, "-")
|
|
18
|
+
.split("-")
|
|
19
|
+
.filter(Boolean)
|
|
20
|
+
.map((p) => p.charAt(0).toUpperCase() + p.slice(1))
|
|
21
|
+
.join("");
|
|
22
|
+
}
|
|
23
|
+
/** Project a DNA model coordinate → a Bedrock `FoundationModel` id. Bedrock
|
|
24
|
+
* encodes the provider inside the id (`anthropic.claude-v2`), so a DNA
|
|
25
|
+
* `prov:model` / `prov/model` provider token is dropped; a bare coordinate
|
|
26
|
+
* passes through unchanged. */
|
|
27
|
+
export function bedrockModelId(model) {
|
|
28
|
+
if (!model)
|
|
29
|
+
return null;
|
|
30
|
+
const ident = model.trim();
|
|
31
|
+
if (ident.toLowerCase().startsWith("arn:"))
|
|
32
|
+
return ident; // ARN — never split.
|
|
33
|
+
const slash = ident.indexOf("/");
|
|
34
|
+
if (slash >= 0)
|
|
35
|
+
return ident.slice(slash + 1).trim(); // DNA slash coordinate.
|
|
36
|
+
const colon = ident.indexOf(":");
|
|
37
|
+
if (colon >= 0) {
|
|
38
|
+
const token = ident.slice(0, colon).trim().toLowerCase();
|
|
39
|
+
if (DNA_PROVIDER_TOKENS.has(token))
|
|
40
|
+
return ident.slice(colon + 1).trim();
|
|
41
|
+
}
|
|
42
|
+
return ident; // bare / Bedrock-native id (keeps any `:version`).
|
|
43
|
+
}
|
|
44
|
+
/** Project a Tool's input JSON Schema → Bedrock `Function.Parameters`
|
|
45
|
+
* (`{name: {Type, Description, Required}}`). Returns the map + whether any type
|
|
46
|
+
* was coerced (for the loss report). */
|
|
47
|
+
export function emitParameters(inputSchema) {
|
|
48
|
+
const props = inputSchema?.properties;
|
|
49
|
+
if (!props || typeof props !== "object" || Object.keys(props).length === 0) {
|
|
50
|
+
return { params: {}, coerced: false };
|
|
51
|
+
}
|
|
52
|
+
const required = Array.isArray(inputSchema.required) ? inputSchema.required : [];
|
|
53
|
+
const requiredSet = new Set(required);
|
|
54
|
+
const out = {};
|
|
55
|
+
let coerced = false;
|
|
56
|
+
for (const [pname, raw] of Object.entries(props)) {
|
|
57
|
+
const pschema = (raw && typeof raw === "object" ? raw : {});
|
|
58
|
+
const jtype = pschema.type ?? "string";
|
|
59
|
+
let btype;
|
|
60
|
+
if (BEDROCK_PARAM_TYPES.has(jtype)) {
|
|
61
|
+
btype = jtype;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
btype = "string"; // object / unknown → flatten to string (recorded loss)
|
|
65
|
+
coerced = true;
|
|
66
|
+
}
|
|
67
|
+
const detail = { Type: btype };
|
|
68
|
+
if (pschema.description)
|
|
69
|
+
detail.Description = pschema.description;
|
|
70
|
+
detail.Required = requiredSet.has(pname);
|
|
71
|
+
out[pname] = detail;
|
|
72
|
+
}
|
|
73
|
+
return { params: out, coerced };
|
|
74
|
+
}
|
|
75
|
+
/** Project the agent's tools → a single Bedrock action group. The executor is
|
|
76
|
+
* `CustomControl: RETURN_CONTROL` — Bedrock returns the tool call to the CALLER
|
|
77
|
+
* (the faithful mapping for DNA's client-side tools; no Lambda ARN needed). */
|
|
78
|
+
function emitActionGroups(ctx) {
|
|
79
|
+
const functions = [];
|
|
80
|
+
let anyCoerced = false;
|
|
81
|
+
for (const t of ctx.tools) {
|
|
82
|
+
const fn = { Name: t.name };
|
|
83
|
+
if (t.description)
|
|
84
|
+
fn.Description = t.description;
|
|
85
|
+
const { params, coerced } = emitParameters((t.parameters ?? {}));
|
|
86
|
+
anyCoerced = anyCoerced || coerced;
|
|
87
|
+
if (Object.keys(params).length > 0)
|
|
88
|
+
fn.Parameters = params;
|
|
89
|
+
functions.push(fn);
|
|
90
|
+
}
|
|
91
|
+
const group = {
|
|
92
|
+
ActionGroupName: `${ctx.name}-actions`,
|
|
93
|
+
Description: `DNA-emitted tools for agent ${ctx.name}`,
|
|
94
|
+
ActionGroupExecutor: { CustomControl: "RETURN_CONTROL" },
|
|
95
|
+
FunctionSchema: { Functions: functions },
|
|
96
|
+
};
|
|
97
|
+
return { groups: [group], coerced: anyCoerced };
|
|
98
|
+
}
|
|
99
|
+
export class BedrockEmitter {
|
|
100
|
+
target = "bedrock";
|
|
101
|
+
fileExtension = "bedrock.json";
|
|
102
|
+
/** The PURE de-para: {@link EmitContext} → the CloudFormation object. Field
|
|
103
|
+
* order is intentional and preserved by JSON.stringify (insertion order). */
|
|
104
|
+
toTemplate(ctx) {
|
|
105
|
+
const logicalId = `${camel(ctx.name)}Agent`;
|
|
106
|
+
const props = { AgentName: ctx.name };
|
|
107
|
+
if (ctx.description)
|
|
108
|
+
props.Description = ctx.description;
|
|
109
|
+
const modelId = bedrockModelId(ctx.model);
|
|
110
|
+
if (modelId)
|
|
111
|
+
props.FoundationModel = modelId;
|
|
112
|
+
props.Instruction = ctx.instructions; // verbatim — the byte-equal gate
|
|
113
|
+
if (ctx.tools.length > 0)
|
|
114
|
+
props.ActionGroups = emitActionGroups(ctx).groups;
|
|
115
|
+
props.AutoPrepare = true;
|
|
116
|
+
return {
|
|
117
|
+
AWSTemplateFormatVersion: CFN_VERSION,
|
|
118
|
+
Description: `DNA-emitted Amazon Bedrock Agent: ${ctx.name}`,
|
|
119
|
+
Resources: {
|
|
120
|
+
[logicalId]: { Type: "AWS::Bedrock::Agent", Properties: props },
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
emit(ctx) {
|
|
125
|
+
const template = this.toTemplate(ctx);
|
|
126
|
+
const artifact = JSON.stringify(template, null, 2) + "\n";
|
|
127
|
+
const losses = [
|
|
128
|
+
"composition structure — Soul reuse + wired Guardrails flatten to one " +
|
|
129
|
+
"`Instruction` string (Bedrock `GuardrailConfiguration` is an " +
|
|
130
|
+
"ID-referenced Bedrock Guardrail, not DNA's composed guardrails)",
|
|
131
|
+
"tenant overlay — a per-tenant persona without a fork has no Bedrock Agent field",
|
|
132
|
+
"eval-as-contract — prompt invariants (EvalCases) have no Bedrock slot",
|
|
133
|
+
];
|
|
134
|
+
if (ctx.tools.length > 0) {
|
|
135
|
+
losses.push("tool parameter depth — Bedrock `ParameterDetail` is a flat " +
|
|
136
|
+
"{Type, Description, Required} map (Type ∈ string|number|integer|" +
|
|
137
|
+
"boolean|array); JSON-Schema `default`, `enum`, nested object " +
|
|
138
|
+
"`properties`, and array `items` typing are dropped");
|
|
139
|
+
}
|
|
140
|
+
if (ctx.outputSchema) {
|
|
141
|
+
losses.push("output_schema — Bedrock Agent has no structured-response / " +
|
|
142
|
+
"output-schema field; the agent's typed output contract is dropped");
|
|
143
|
+
}
|
|
144
|
+
if (ctx.model === null) {
|
|
145
|
+
losses.push("model unbound in DNA and none supplied — emitted template has no " +
|
|
146
|
+
"`FoundationModel`; pass provider/model or set spec.model / Genome default_llm");
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
losses.push("model coordinate — a DNA `azure/openai` coordinate is not a Bedrock " +
|
|
150
|
+
"foundation-model id; `FoundationModel` needs a Bedrock model id or " +
|
|
151
|
+
"inference-profile ARN, plus an `AgentResourceRoleArn` at deploy");
|
|
152
|
+
}
|
|
153
|
+
const mapping = {
|
|
154
|
+
"metadata.name": "Resources.<id>Agent.Properties.AgentName",
|
|
155
|
+
"metadata.description": "Properties.Description",
|
|
156
|
+
"buildPrompt (Soul+guardrails+instruction)": "Properties.Instruction (byte-equal)",
|
|
157
|
+
"spec.model / Genome.default_llm": "Properties.FoundationModel",
|
|
158
|
+
"spec.tools[] (Tool Kind)": "Properties.ActionGroups[].FunctionSchema.Functions[]",
|
|
159
|
+
"Tool.input_schema.properties": "Function.Parameters{Type,Description,Required}",
|
|
160
|
+
};
|
|
161
|
+
return {
|
|
162
|
+
artifact,
|
|
163
|
+
target: this.target,
|
|
164
|
+
filename: `${ctx.name}.${this.fileExtension}`,
|
|
165
|
+
losses,
|
|
166
|
+
mapping,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
}
|
package/dist/emit/index.js
CHANGED
|
@@ -20,9 +20,11 @@ async function ensureBuiltins() {
|
|
|
20
20
|
return;
|
|
21
21
|
builtinsWired = true;
|
|
22
22
|
const { AgentFrameworkEmitter } = await import("./agentFramework.js");
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
EMITTER_REGISTRY.
|
|
23
|
+
const { BedrockEmitter } = await import("./bedrock.js");
|
|
24
|
+
for (const e of [new AgentFrameworkEmitter(), new BedrockEmitter()]) {
|
|
25
|
+
if (!EMITTER_REGISTRY.has(e.target))
|
|
26
|
+
EMITTER_REGISTRY.set(e.target, e);
|
|
27
|
+
}
|
|
26
28
|
}
|
|
27
29
|
/** Register an emitter under its `target` (last registration wins). */
|
|
28
30
|
export function registerEmitter(emitter) {
|
|
@@ -101,6 +101,14 @@ class ResearchKind extends KindBase {
|
|
|
101
101
|
items: { type: "string" },
|
|
102
102
|
default: [],
|
|
103
103
|
},
|
|
104
|
+
cited_by: {
|
|
105
|
+
type: "array",
|
|
106
|
+
items: { type: "string" },
|
|
107
|
+
default: [],
|
|
108
|
+
description: "Kind/name of docs that cite this Research as a grounding source. " +
|
|
109
|
+
"Auto-maintained by `dna sdlc cite Research/<name> --from <Kind>/<name>` " +
|
|
110
|
+
"— don't author by hand.",
|
|
111
|
+
},
|
|
104
112
|
findings: {
|
|
105
113
|
type: "array",
|
|
106
114
|
items: {
|
package/dist/index.d.ts
CHANGED
|
@@ -29,6 +29,7 @@ export type { ToolSurface } from "./tools.js";
|
|
|
29
29
|
export { emitAgent, buildEmitContext, registerEmitter, getEmitter, availableTargets, EmitError, UnknownTarget, } from "./emit/index.js";
|
|
30
30
|
export type { EmitContext, EmitResult, EmitTool, EmitterPort, BuildEmitContextOpts, } from "./emit/index.js";
|
|
31
31
|
export { AgentFrameworkEmitter } from "./emit/agentFramework.js";
|
|
32
|
+
export { BedrockEmitter } from "./emit/bedrock.js";
|
|
32
33
|
export type { LoadPromptsOptions } from "./prompts.js";
|
|
33
34
|
export { anchorScopesRoot, PackageScopeNotFound, DEFAULT_SUBPATH } from "./package-scope.js";
|
|
34
35
|
export { loadConfig, findConfig, CONFIG_FILENAME } from "./config.js";
|
package/dist/index.js
CHANGED
|
@@ -32,6 +32,7 @@ export { PromptLibrary, loadPrompts } from "./prompts.js";
|
|
|
32
32
|
export { ToolLibrary, loadTools } from "./tools.js";
|
|
33
33
|
export { emitAgent, buildEmitContext, registerEmitter, getEmitter, availableTargets, EmitError, UnknownTarget, } from "./emit/index.js";
|
|
34
34
|
export { AgentFrameworkEmitter } from "./emit/agentFramework.js";
|
|
35
|
+
export { BedrockEmitter } from "./emit/bedrock.js";
|
|
35
36
|
export { anchorScopesRoot, PackageScopeNotFound, DEFAULT_SUBPATH } from "./package-scope.js";
|
|
36
37
|
export { loadConfig, findConfig, CONFIG_FILENAME } from "./config.js";
|
|
37
38
|
export { sourceFromUrl, resolveDefaultFsUrl, UnsupportedSourceScheme } from "./adapters/source-url.js";
|