@promptev/context-engine 0.0.4 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -0
- package/dist/cli.js +205 -21
- package/dist/cli.js.map +1 -1
- package/dist/express.cjs +205 -21
- package/dist/express.cjs.map +1 -1
- package/dist/express.js +205 -21
- package/dist/express.js.map +1 -1
- package/dist/fastify.cjs +205 -21
- package/dist/fastify.cjs.map +1 -1
- package/dist/fastify.js +205 -21
- package/dist/fastify.js.map +1 -1
- package/dist/hono.cjs +205 -21
- package/dist/hono.cjs.map +1 -1
- package/dist/hono.js +205 -21
- package/dist/hono.js.map +1 -1
- package/dist/index.cjs +223 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +33 -1
- package/dist/index.d.ts +33 -1
- package/dist/index.js +222 -23
- package/dist/index.js.map +1 -1
- package/dist/skills/context-engine/SKILL.md +25 -0
- package/package.json +1 -1
- package/src/skills/context-engine/SKILL.md +25 -0
package/dist/hono.js
CHANGED
|
@@ -944,7 +944,7 @@ var SCHEMAS = {
|
|
|
944
944
|
url: { type: "string", description: "Endpoint URL, may contain {path} params" },
|
|
945
945
|
method: {
|
|
946
946
|
type: "string",
|
|
947
|
-
enum: ["GET", "POST", "PUT", "PATCH", "DELETE"],
|
|
947
|
+
enum: ["GET", "POST", "PUT", "PATCH", "DELETE", "QUERY"],
|
|
948
948
|
default: "GET"
|
|
949
949
|
},
|
|
950
950
|
headers: {
|
|
@@ -980,6 +980,15 @@ var SCHEMAS = {
|
|
|
980
980
|
llmQueryParameters: {
|
|
981
981
|
type: "object",
|
|
982
982
|
description: "LLM-filled parameters sent as the query string"
|
|
983
|
+
},
|
|
984
|
+
// How the response comes back to the caller, whatever the method. `tsv`
|
|
985
|
+
// turns every array of objects in it into a TSV string (`formatResult`
|
|
986
|
+
// in tools/response-mode.ts); a caller's explicit `responseMode` wins.
|
|
987
|
+
response_mode: {
|
|
988
|
+
type: "string",
|
|
989
|
+
enum: ["json", "tsv"],
|
|
990
|
+
default: "json",
|
|
991
|
+
description: "Return the response as JSON, or its arrays of objects as TSV"
|
|
983
992
|
}
|
|
984
993
|
},
|
|
985
994
|
required: ["url", "method"]
|
|
@@ -2507,6 +2516,77 @@ function findTool(tools, callName) {
|
|
|
2507
2516
|
return tools.find((t) => t.callName === callName);
|
|
2508
2517
|
}
|
|
2509
2518
|
|
|
2519
|
+
// src/tools/response-mode.ts
|
|
2520
|
+
var RESPONSE_MODES = ["json", "tsv"];
|
|
2521
|
+
function validateResponseMode(value, name = "responseMode") {
|
|
2522
|
+
if (!RESPONSE_MODES.includes(value)) {
|
|
2523
|
+
throw new Error(`${name} must be one of json, tsv, got ${JSON.stringify(value)}`);
|
|
2524
|
+
}
|
|
2525
|
+
return value;
|
|
2526
|
+
}
|
|
2527
|
+
function tsvCell(value) {
|
|
2528
|
+
if (value === null || value === void 0) return "\\N";
|
|
2529
|
+
let text;
|
|
2530
|
+
if (typeof value === "string") text = value;
|
|
2531
|
+
else if (value instanceof Date) text = value.toISOString();
|
|
2532
|
+
else if (typeof value === "bigint") text = value.toString();
|
|
2533
|
+
else {
|
|
2534
|
+
try {
|
|
2535
|
+
text = JSON.stringify(value) ?? String(value);
|
|
2536
|
+
} catch {
|
|
2537
|
+
text = String(value);
|
|
2538
|
+
}
|
|
2539
|
+
}
|
|
2540
|
+
return text.replaceAll("\\", "\\\\").replaceAll(" ", "\\t").replaceAll("\n", "\\n").replaceAll("\r", "\\r");
|
|
2541
|
+
}
|
|
2542
|
+
function isPlainObject2(value) {
|
|
2543
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
2544
|
+
const proto = Object.getPrototypeOf(value);
|
|
2545
|
+
return proto === Object.prototype || proto === null;
|
|
2546
|
+
}
|
|
2547
|
+
function isTable(value) {
|
|
2548
|
+
return Array.isArray(value) && value.length > 0 && value.every(isPlainObject2);
|
|
2549
|
+
}
|
|
2550
|
+
function tsvLines(rows) {
|
|
2551
|
+
const columns = [];
|
|
2552
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2553
|
+
for (const row of rows) {
|
|
2554
|
+
for (const key of Object.keys(row)) {
|
|
2555
|
+
if (!seen.has(key)) {
|
|
2556
|
+
seen.add(key);
|
|
2557
|
+
columns.push(key);
|
|
2558
|
+
}
|
|
2559
|
+
}
|
|
2560
|
+
}
|
|
2561
|
+
return [
|
|
2562
|
+
columns.map(tsvCell).join(" "),
|
|
2563
|
+
...rows.map((row) => columns.map((c) => tsvCell(row[c])).join(" "))
|
|
2564
|
+
];
|
|
2565
|
+
}
|
|
2566
|
+
function collectTables(value, path, out) {
|
|
2567
|
+
if (isTable(value)) {
|
|
2568
|
+
out.set(JSON.stringify(path), { path, lines: tsvLines(value) });
|
|
2569
|
+
} else if (isPlainObject2(value)) {
|
|
2570
|
+
for (const [key, child] of Object.entries(value)) collectTables(child, [...path, key], out);
|
|
2571
|
+
} else if (Array.isArray(value)) {
|
|
2572
|
+
value.forEach((child, index) => {
|
|
2573
|
+
collectTables(child, [...path, index], out);
|
|
2574
|
+
});
|
|
2575
|
+
}
|
|
2576
|
+
}
|
|
2577
|
+
function buildTsv(value, path, tables, kept) {
|
|
2578
|
+
const id = JSON.stringify(path);
|
|
2579
|
+
const table = tables.get(id);
|
|
2580
|
+
if (table) return table.lines.slice(0, (kept.get(id) ?? 0) + 1).join("\n");
|
|
2581
|
+
if (isPlainObject2(value)) {
|
|
2582
|
+
const out = {};
|
|
2583
|
+
for (const [k, v] of Object.entries(value)) out[k] = buildTsv(v, [...path, k], tables, kept);
|
|
2584
|
+
return out;
|
|
2585
|
+
}
|
|
2586
|
+
if (Array.isArray(value)) return value.map((v, i) => buildTsv(v, [...path, i], tables, kept));
|
|
2587
|
+
return value;
|
|
2588
|
+
}
|
|
2589
|
+
|
|
2510
2590
|
// src/tools/governance.ts
|
|
2511
2591
|
var RESULT_MAX_CHARS = 8e3;
|
|
2512
2592
|
var RESULT_MAX_ROWS = 100;
|
|
@@ -2538,12 +2618,90 @@ function stripUnderscoreArgs(args) {
|
|
|
2538
2618
|
}
|
|
2539
2619
|
return out;
|
|
2540
2620
|
}
|
|
2621
|
+
function validateResultBudget(name, value, fallback) {
|
|
2622
|
+
if (value === void 0) return fallback;
|
|
2623
|
+
if (value === null) return null;
|
|
2624
|
+
if (typeof value !== "number" || !Number.isInteger(value)) {
|
|
2625
|
+
throw new TypeError(`${name} must be a positive integer or null, got ${typeof value}`);
|
|
2626
|
+
}
|
|
2627
|
+
if (value < 1) throw new Error(`${name} must be a positive integer or null, got ${value}`);
|
|
2628
|
+
return value;
|
|
2629
|
+
}
|
|
2630
|
+
function serialize(value) {
|
|
2631
|
+
try {
|
|
2632
|
+
return JSON.stringify(value) ?? JSON.stringify(String(value));
|
|
2633
|
+
} catch {
|
|
2634
|
+
return JSON.stringify(String(value));
|
|
2635
|
+
}
|
|
2636
|
+
}
|
|
2637
|
+
function clip(serialized, maxChars) {
|
|
2638
|
+
return {
|
|
2639
|
+
_truncated: serialized.slice(0, maxChars),
|
|
2640
|
+
_original_size: serialized.length,
|
|
2641
|
+
_note: "tool result exceeded the context budget and was truncated"
|
|
2642
|
+
};
|
|
2643
|
+
}
|
|
2644
|
+
function shapeTsv(result, maxChars, maxRows) {
|
|
2645
|
+
const wrapped = !isPlainObject2(result);
|
|
2646
|
+
const root = wrapped ? { result } : result;
|
|
2647
|
+
const tables = /* @__PURE__ */ new Map();
|
|
2648
|
+
collectTables(root, [], tables);
|
|
2649
|
+
if (!tables.size) return null;
|
|
2650
|
+
const sizes = new Map([...tables].map(([id, t]) => [id, t.lines.length - 1]));
|
|
2651
|
+
const kept = new Map([...sizes].map(([id, n]) => [id, maxRows === null ? n : Math.min(n, maxRows)]));
|
|
2652
|
+
const render = () => {
|
|
2653
|
+
const built = buildTsv(root, [], tables, kept);
|
|
2654
|
+
const notes = {};
|
|
2655
|
+
for (const [id, t] of tables) {
|
|
2656
|
+
const k = kept.get(id);
|
|
2657
|
+
const n = sizes.get(id);
|
|
2658
|
+
if (k < n) notes[t.path.join(".")] = { rows_returned: k, rows_omitted: n - k };
|
|
2659
|
+
}
|
|
2660
|
+
if (Object.keys(notes).length) {
|
|
2661
|
+
built._result_shaping = notes;
|
|
2662
|
+
return built;
|
|
2663
|
+
}
|
|
2664
|
+
return wrapped ? built.result : built;
|
|
2665
|
+
};
|
|
2666
|
+
const fits = () => maxChars === null || serialize(render()).length <= maxChars;
|
|
2667
|
+
const capped = [...tables.keys()].some((id) => kept.get(id) < sizes.get(id));
|
|
2668
|
+
if (fits()) return [render(), capped];
|
|
2669
|
+
const initial = new Map(kept);
|
|
2670
|
+
const tableSize = (id) => tables.get(id).lines.slice(0, kept.get(id) + 1).join("\n").length;
|
|
2671
|
+
const bySize = [...tables.keys()].sort((a, b) => tableSize(b) - tableSize(a));
|
|
2672
|
+
for (const id of bySize) {
|
|
2673
|
+
let lo = 0;
|
|
2674
|
+
let hi = kept.get(id) - 1;
|
|
2675
|
+
let best = null;
|
|
2676
|
+
while (lo <= hi) {
|
|
2677
|
+
const mid = Math.floor((lo + hi) / 2);
|
|
2678
|
+
kept.set(id, mid);
|
|
2679
|
+
if (fits()) {
|
|
2680
|
+
best = mid;
|
|
2681
|
+
lo = mid + 1;
|
|
2682
|
+
} else {
|
|
2683
|
+
hi = mid - 1;
|
|
2684
|
+
}
|
|
2685
|
+
}
|
|
2686
|
+
if (best !== null) {
|
|
2687
|
+
kept.set(id, best);
|
|
2688
|
+
return [render(), true];
|
|
2689
|
+
}
|
|
2690
|
+
kept.set(id, 0);
|
|
2691
|
+
}
|
|
2692
|
+
for (const [id, n] of initial) kept.set(id, n);
|
|
2693
|
+
return [clip(serialize(render()), maxChars), true];
|
|
2694
|
+
}
|
|
2541
2695
|
function shapeResult(result, opts = {}) {
|
|
2542
|
-
const maxChars = opts.maxChars
|
|
2543
|
-
const maxRows = opts.maxRows
|
|
2696
|
+
const maxChars = opts.maxChars === void 0 ? RESULT_MAX_CHARS : opts.maxChars;
|
|
2697
|
+
const maxRows = opts.maxRows === void 0 ? RESULT_MAX_ROWS : opts.maxRows;
|
|
2698
|
+
if (opts.responseMode === "tsv") {
|
|
2699
|
+
const tsv = shapeTsv(result, maxChars, maxRows);
|
|
2700
|
+
if (tsv) return tsv;
|
|
2701
|
+
}
|
|
2544
2702
|
let truncated = false;
|
|
2545
2703
|
let shaped = result;
|
|
2546
|
-
if (result && typeof result === "object" && Array.isArray(result.rows) && result.rows.length > maxRows) {
|
|
2704
|
+
if (maxRows !== null && result && typeof result === "object" && Array.isArray(result.rows) && result.rows.length > maxRows) {
|
|
2547
2705
|
const rows = result.rows;
|
|
2548
2706
|
const kept = rows.slice(0, maxRows);
|
|
2549
2707
|
shaped = {
|
|
@@ -2553,22 +2711,9 @@ function shapeResult(result, opts = {}) {
|
|
|
2553
2711
|
};
|
|
2554
2712
|
truncated = true;
|
|
2555
2713
|
}
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
} catch {
|
|
2560
|
-
serialized = JSON.stringify(String(shaped));
|
|
2561
|
-
}
|
|
2562
|
-
if (serialized.length > maxChars) {
|
|
2563
|
-
return [
|
|
2564
|
-
{
|
|
2565
|
-
_truncated: serialized.slice(0, maxChars),
|
|
2566
|
-
_original_size: serialized.length,
|
|
2567
|
-
_note: "tool result exceeded the context budget and was truncated"
|
|
2568
|
-
},
|
|
2569
|
-
true
|
|
2570
|
-
];
|
|
2571
|
-
}
|
|
2714
|
+
if (maxChars === null) return [shaped, truncated];
|
|
2715
|
+
const serialized = serialize(shaped);
|
|
2716
|
+
if (serialized.length > maxChars) return [clip(serialized, maxChars), true];
|
|
2572
2717
|
return [shaped, truncated];
|
|
2573
2718
|
}
|
|
2574
2719
|
function redactToolResult(result, policy, opts) {
|
|
@@ -2671,9 +2816,29 @@ async function mergedTools(engine, sourceId) {
|
|
|
2671
2816
|
const functions = Object.values(engine._functionTools ?? {});
|
|
2672
2817
|
return [...persisted, ...functions];
|
|
2673
2818
|
}
|
|
2819
|
+
function configuredResponseMode(ct, config) {
|
|
2820
|
+
if (ct.kind !== "http" || config.response_mode == null) return "json";
|
|
2821
|
+
try {
|
|
2822
|
+
return validateResponseMode(config.response_mode, "config.response_mode");
|
|
2823
|
+
} catch {
|
|
2824
|
+
console.warn(
|
|
2825
|
+
`tool ${ct.callName} has an unknown config response_mode ${JSON.stringify(config.response_mode)}; returning json`
|
|
2826
|
+
);
|
|
2827
|
+
return "json";
|
|
2828
|
+
}
|
|
2829
|
+
}
|
|
2830
|
+
function checkConfigResponseMode(kind, config) {
|
|
2831
|
+
if (kind !== "http" || !config || config.response_mode == null) return;
|
|
2832
|
+
try {
|
|
2833
|
+
validateResponseMode(config.response_mode, "config.response_mode");
|
|
2834
|
+
} catch (exc) {
|
|
2835
|
+
throw new ConfigTemplateError(exc.message);
|
|
2836
|
+
}
|
|
2837
|
+
}
|
|
2674
2838
|
async function registerTool(engine, tc) {
|
|
2675
2839
|
canonicalFromConfig(tc);
|
|
2676
2840
|
const config = tc.config ?? {};
|
|
2841
|
+
checkConfigResponseMode(tc.kind, config);
|
|
2677
2842
|
if (containsSentinel(config)) {
|
|
2678
2843
|
throw new ConfigTemplateError(
|
|
2679
2844
|
`config contains the ${JSON.stringify(REDACTED_SENTINEL)} placeholder \u2014 a redacted template cannot be registered as a new tool; re-enter the secret values`
|
|
@@ -2709,6 +2874,12 @@ async function updateTool(engine, id, opts) {
|
|
|
2709
2874
|
if (!row || !aclVisible(row.acl != null ? [...row.acl] : null, principals)) {
|
|
2710
2875
|
throw new EngineActionError(`tool not found: ${id}`);
|
|
2711
2876
|
}
|
|
2877
|
+
if ("config" in fields) {
|
|
2878
|
+
checkConfigResponseMode(
|
|
2879
|
+
"kind" in fields ? fields.kind : row.kind,
|
|
2880
|
+
fields.config
|
|
2881
|
+
);
|
|
2882
|
+
}
|
|
2712
2883
|
const sets = [];
|
|
2713
2884
|
const params = [];
|
|
2714
2885
|
let i = 1;
|
|
@@ -2999,6 +3170,9 @@ function warnUnscopedApproval(callName) {
|
|
|
2999
3170
|
async function executeTool(engine, callName, args, opts = {}) {
|
|
3000
3171
|
const runtimeArgs = args ?? {};
|
|
3001
3172
|
const approvalScope = validateApprovalScope(opts.approvalScope);
|
|
3173
|
+
const resultMaxChars = validateResultBudget("resultMaxChars", opts.resultMaxChars, RESULT_MAX_CHARS);
|
|
3174
|
+
const resultMaxRows = validateResultBudget("resultMaxRows", opts.resultMaxRows, RESULT_MAX_ROWS);
|
|
3175
|
+
let responseMode = opts.responseMode === void 0 || opts.responseMode === null ? null : validateResponseMode(opts.responseMode);
|
|
3002
3176
|
const ct = findTool(await mergedTools(engine, opts.sourceId ?? null), callName);
|
|
3003
3177
|
if (!ct) throw new EngineActionError(`tool not found: ${callName}`);
|
|
3004
3178
|
if (!toolVisible(ct, opts.principals ?? null)) {
|
|
@@ -3041,6 +3215,7 @@ async function executeTool(engine, callName, args, opts = {}) {
|
|
|
3041
3215
|
if (ct.kind !== "function" && ct.id != null) {
|
|
3042
3216
|
config = await decryptCtConfig(engine, ct.id);
|
|
3043
3217
|
}
|
|
3218
|
+
responseMode ??= configuredResponseMode(ct, config);
|
|
3044
3219
|
const actorType = opts.actor?.type ?? null;
|
|
3045
3220
|
const actorId = opts.actor?.id ?? null;
|
|
3046
3221
|
let rawResult = null;
|
|
@@ -3064,7 +3239,16 @@ async function executeTool(engine, callName, args, opts = {}) {
|
|
|
3064
3239
|
hooks: engine.hooks
|
|
3065
3240
|
});
|
|
3066
3241
|
rawResult = redacted;
|
|
3067
|
-
|
|
3242
|
+
let toShape = rawResult;
|
|
3243
|
+
if (responseMode === "tsv" && ct.kind === "db" && isPlainObject2(rawResult)) {
|
|
3244
|
+
const { text: _preview, ...rest } = rawResult;
|
|
3245
|
+
toShape = rest;
|
|
3246
|
+
}
|
|
3247
|
+
[shaped, truncated] = shapeResult(toShape, {
|
|
3248
|
+
maxChars: resultMaxChars,
|
|
3249
|
+
maxRows: resultMaxRows,
|
|
3250
|
+
responseMode
|
|
3251
|
+
});
|
|
3068
3252
|
} catch (e) {
|
|
3069
3253
|
exc = e;
|
|
3070
3254
|
success = false;
|