@noodleseed/one 0.146.0 → 0.147.1

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.
@@ -1,8 +1,10 @@
1
1
  import { splitResultMeta } from '@noodle-borg/runtime';
2
2
  import { isCredentialShapedAssistantText } from './assistant-sensitive-values.js';
3
- const MAX_PRESENTATION_BYTES = 16 * 1024;
3
+ const MAX_REVIEW_BYTES = 16 * 1024;
4
+ const MAX_OUTPUT_BYTES = 64 * 1024;
4
5
  const MAX_DEPTH = 8;
5
- const MAX_CONTAINER_ENTRIES = 128;
6
+ const MAX_REVIEW_CONTAINER_ENTRIES = 128;
7
+ const MAX_OUTPUT_CONTAINER_ENTRIES = 512;
6
8
  const MAX_STRING_LENGTH = 2_048;
7
9
  const SENSITIVE_KEY = /(?:secret|token|api[-_]?key|password|credential|authorization|cookie)/i;
8
10
  /** Derive a client-visible review while retaining the exact validated arguments only in the store. */
@@ -87,17 +89,22 @@ export function assistantSafeOutput(schema, value) {
87
89
  }
88
90
  function boundedProjection(schema, value, label) {
89
91
  const state = { complete: true };
90
- const projected = project(schema, value, 0, new Set(), state);
92
+ const maxBytes = label === 'REVIEW' ? MAX_REVIEW_BYTES : MAX_OUTPUT_BYTES;
93
+ const maxContainerEntries = label === 'REVIEW' ? MAX_REVIEW_CONTAINER_ENTRIES : MAX_OUTPUT_CONTAINER_ENTRIES;
94
+ const projected = project(schema, value, 0, new Set(), state, maxContainerEntries);
91
95
  try {
92
96
  const encoded = JSON.stringify(projected);
93
- if (new TextEncoder().encode(encoded).byteLength <= MAX_PRESENTATION_BYTES) {
97
+ if (new TextEncoder().encode(encoded).byteLength <= maxBytes) {
94
98
  return { value: projected, complete: state.complete };
95
99
  }
96
100
  }
97
101
  catch {
98
102
  // Fall through to the safe omission marker.
99
103
  }
100
- return { value: { notice: `[${label} OMITTED: exceeds 16 KiB]` }, complete: false };
104
+ return {
105
+ value: { notice: `[${label} OMITTED: exceeds ${maxBytes / 1024} KiB]` },
106
+ complete: false,
107
+ };
101
108
  }
102
109
  function presentationSchema(schema, depth = 0) {
103
110
  if (depth >= MAX_DEPTH)
@@ -116,7 +123,7 @@ function presentationSchema(schema, depth = 0) {
116
123
  }
117
124
  if (isRecord(schema.properties)) {
118
125
  result.properties = Object.fromEntries(Object.entries(schema.properties)
119
- .slice(0, MAX_CONTAINER_ENTRIES)
126
+ .slice(0, MAX_REVIEW_CONTAINER_ENTRIES)
120
127
  .map(([name, value]) => [
121
128
  name,
122
129
  isRecord(value) ? presentationSchema(value, depth + 1) : {},
@@ -126,7 +133,7 @@ function presentationSchema(schema, depth = 0) {
126
133
  result.items = presentationSchema(schema.items, depth + 1);
127
134
  if (depth === 0) {
128
135
  try {
129
- if (new TextEncoder().encode(JSON.stringify(result)).byteLength > MAX_PRESENTATION_BYTES) {
136
+ if (new TextEncoder().encode(JSON.stringify(result)).byteLength > MAX_REVIEW_BYTES) {
130
137
  return typeof result.type === 'string' ? { type: result.type } : {};
131
138
  }
132
139
  }
@@ -139,7 +146,7 @@ function presentationSchema(schema, depth = 0) {
139
146
  function isRecord(value) {
140
147
  return value !== null && typeof value === 'object' && !Array.isArray(value);
141
148
  }
142
- function project(schema, value, depth, ancestors, state) {
149
+ function project(schema, value, depth, ancestors, state, maxContainerEntries) {
143
150
  if (isSensitiveSchema(schema))
144
151
  return '[REDACTED]';
145
152
  if (typeof value === 'string') {
@@ -172,9 +179,9 @@ function project(schema, value, depth, ancestors, state) {
172
179
  if (Array.isArray(value)) {
173
180
  const itemSchema = recordValue(schema?.items);
174
181
  const result = value
175
- .slice(0, MAX_CONTAINER_ENTRIES)
176
- .map((entry) => project(itemSchema, entry, depth + 1, ancestors, state));
177
- if (value.length > MAX_CONTAINER_ENTRIES) {
182
+ .slice(0, maxContainerEntries)
183
+ .map((entry) => project(itemSchema, entry, depth + 1, ancestors, state, maxContainerEntries));
184
+ if (value.length > maxContainerEntries) {
178
185
  state.complete = false;
179
186
  result.push('[TRUNCATED: more entries]');
180
187
  }
@@ -183,7 +190,7 @@ function project(schema, value, depth, ancestors, state) {
183
190
  }
184
191
  const properties = recordValue(schema?.properties);
185
192
  const result = Object.create(null);
186
- const entries = Object.entries(value).slice(0, MAX_CONTAINER_ENTRIES);
193
+ const entries = Object.entries(value).slice(0, maxContainerEntries);
187
194
  for (const [key, entry] of entries) {
188
195
  const propertySchema = ownRecordValue(properties, key);
189
196
  if (SENSITIVE_KEY.test(key) && !isSensitiveSchema(propertySchema)) {
@@ -191,10 +198,10 @@ function project(schema, value, depth, ancestors, state) {
191
198
  result[key] = '[REDACTED]';
192
199
  }
193
200
  else {
194
- result[key] = project(propertySchema, entry, depth + 1, ancestors, state);
201
+ result[key] = project(propertySchema, entry, depth + 1, ancestors, state, maxContainerEntries);
195
202
  }
196
203
  }
197
- if (Object.keys(value).length > MAX_CONTAINER_ENTRIES) {
204
+ if (Object.keys(value).length > maxContainerEntries) {
198
205
  state.complete = false;
199
206
  result._truncated = '[TRUNCATED: more properties]';
200
207
  }
@@ -41,7 +41,7 @@
41
41
  "@noodle-borg/module": "0.0.0",
42
42
  "@noodle-borg/protocol": "0.0.0",
43
43
  "@noodle-borg/runtime": "0.0.0",
44
- "@noodleseed/assistant": "1.27.0",
44
+ "@noodleseed/assistant": "1.28.0",
45
45
  "zod": "^4.4.3"
46
46
  },
47
47
  "devDependencies": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noodleseed/assistant",
3
- "version": "1.27.0",
3
+ "version": "1.28.0",
4
4
  "description": "Embed the Noodle Seed customer-branded assistant in your web app with managed or framework-owned UI, a framework-neutral MCP App host, a DOM-free client, and a backend session helper. Authoring and deploying the server is @noodleseed/one.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noodleseed/one",
3
- "version": "0.146.0",
3
+ "version": "0.147.1",
4
4
  "private": false,
5
5
  "description": "Noodle CLI by Noodle Seed — author, run, and deploy declarative MCP servers. Embedding the assistant in your own web app is @noodleseed/assistant.",
6
6
  "license": "Apache-2.0",