@noodleseed/one 0.189.0 → 0.190.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.
@@ -76,6 +76,7 @@ export const ERROR_FIXES = {
76
76
  interaction_field_control_mismatch: 'Match each control to the action input type: `consent` needs `z.literal(true)`, `select` needs `z.enum([...])` of strings, and `text`/`textarea`/`email`/`phone`/`url` need a string schema.',
77
77
  interaction_field_missing: 'Collect or seed every required action input (a `fields` entry or an `initialValues` entry), mark a not-required field `optional: true`, and let an optional-but-required string accept `""`.',
78
78
  interaction_initial_value_unknown: 'Key `initialValues` by an action input property and set `fromOutput` to a property of this opener’s `output` schema.',
79
+ interaction_initial_value_private: 'Remove this `initialValues` entry and let the platform collect the `private: true` field; the opener’s output comes from the model, so seeding a private field would route its value through the model.',
79
80
  interaction_consent_invalid: 'Keep exactly one `control: "consent"` field; the runtime poses one consent question, never several.',
80
81
  interaction_expiry_invalid: 'Set `confirmationExpiry.seconds` to a whole number from 1 to 86400; a developer may only shorten the channel profile’s default.',
81
82
  channel_dependency_missing: 'Select the opener and its `interaction.action` together in the same `publicMessaging({ capabilities })` list; natural collection needs the confirmed action it prepares.',
@@ -182,6 +182,7 @@ export const COMPILE_ERROR_CODES = [
182
182
  'interaction_field_control_mismatch',
183
183
  'interaction_field_missing',
184
184
  'interaction_initial_value_unknown',
185
+ 'interaction_initial_value_private',
185
186
  'interaction_consent_invalid',
186
187
  'interaction_expiry_invalid',
187
188
  'channel_dependency_missing',
@@ -44,7 +44,7 @@ export function renderEmbeddedAssistantReference() {
44
44
  '- `action` is a tool with `annotations.openAction({ confirm: true })` (never read-only) whose fulfilment saves one native record through `connectors.records`.',
45
45
  '- `fields` name the action’s Zod input keys with one of seven controls: `text`, `textarea`, `email`, `phone`, `url`, `select` (a `z.enum` of strings) and `consent` (`z.literal(true)`, at most one; the runtime poses the consent question and never infers it).',
46
46
  '- Nothing is private by default. `private: true` keeps that value out of the conversation model, transcript, logs and diagnostics. `optional: true` lets a person skip a field; an optional field the schema still requires must accept `""`.',
47
- '- `initialValues: { workflow: { fromOutput: "workflow" } }` seeds action inputs from the opener’s `output`; every other required action input must be a field.',
47
+ '- `initialValues: { workflow: { fromOutput: "workflow" } }` seeds action inputs from the opener’s `output`; every other required action input must be a field. Never seed a `private: true` field: the opener’s output comes from the model, so the compiler refuses it and the platform collects that value privately.',
48
48
  '- `confirmationExpiry: { seconds }` may only shorten the channel’s default (ten minutes on WhatsApp), never lengthen it.',
49
49
  '- On `publicMessaging`, list the opener and its action together. The compiler reports `channel_dependency_missing` for an opener selected alone and `channel_requirement_unsupported` for a widget, write or external connector call that has no collect interaction.',
50
50
  '',
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noodle-borg/agent-kit",
3
- "version": "0.113.0",
3
+ "version": "0.113.1",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "engines": {
@@ -42,7 +42,7 @@
42
42
  "@noodle-borg/module-audit": "0.0.0",
43
43
  "@noodle-borg/protocol": "0.0.0",
44
44
  "@noodle-borg/runtime": "0.0.0",
45
- "@noodleseed/assistant": "1.38.0",
45
+ "@noodleseed/assistant": "1.39.0",
46
46
  "zod": "^4.4.3"
47
47
  },
48
48
  "devDependencies": {
@@ -1,7 +1,7 @@
1
1
  import type { AppPackageArtifactV1 } from '@noodle-borg/app-package';
2
2
  import type { RuntimeArtifact } from './artifact/types.js';
3
3
  import type { PackagedAsset } from './assets.js';
4
- export type CompileErrorCode = 'invalid_context_provider' | 'yaml_parse_error' | 'invalid_shape' | 'invalid_name' | 'duplicate_name' | 'reserved_name' | 'unsupported_manifest_version' | 'reserved_for_future_version' | 'invalid_operation_ref' | 'external_ref' | 'invalid_schema_ref' | 'unknown_schema_ref' | 'schema_ref_conflict' | 'invalid_expression' | 'expr_unknown_root' | 'expr_root_unavailable' | 'expr_operator_not_allowed' | 'expr_if_not_boolean' | 'unknown_step_ref' | 'forward_step_ref' | 'self_step_ref' | 'duplicate_step_id' | 'invalid_fulfilment' | 'invalid_elicitation_schema' | 'invalid_elicitation_flow' | 'invalid_confirmation_flow' | 'arg_type_mismatch' | 'ambient_context_action' | 'duplicate_resource' | 'duplicate_prompt' | 'duplicate_resource_uri' | 'unsupported_uri_template' | 'duplicate_widget' | 'unknown_widget_tool' | 'unknown_widget_action_tool' | 'duplicate_widget_tool' | 'invalid_widget_binding' | 'invalid_widget_state_handle' | 'widget_html_too_large' | 'widget_html_total_too_large' | 'invalid_asset' | 'invalid_capability_requirement' | 'state_secret_field' | 'invalid_knowledge' | 'knowledge_unhashed' | 'invalid_managed_collection' | 'invalid_variable_declaration' | 'invalid_managed_collection_source' | 'unknown_connector_alias' | 'connector_not_in_catalog' | 'unknown_operation' | 'connector_binding_required' | 'ambiguous_nested_connector_binding' | 'invalid_connector_call_graph' | 'unsupported_credential_profile' | 'credential_scope_mismatch' | 'credential_audience_mismatch' | 'customer_endpoint_auth_required' | 'customer_endpoint_mapping_required' | 'customer_endpoint_unknown_mapping' | 'customer_endpoint_bridge_unsupported' | 'assistant_messaging_unsupported' | 'assistant_capability_unknown' | 'assistant_public_user_reference' | 'assistant_public_effect_unconfirmed' | 'tool_anonymous_requires_identity' | 'interaction_action_invalid' | 'interaction_field_unknown' | 'interaction_field_control_mismatch' | 'interaction_field_missing' | 'interaction_initial_value_unknown' | 'interaction_consent_invalid' | 'interaction_expiry_invalid' | 'channel_dependency_missing' | 'channel_requirement_unsupported' | 'customer_endpoint_action_unsupported' | 'customer_endpoint_surface_unsupported' | 'customer_endpoint_credential_source_unsupported' | 'customer_endpoint_policy_conflict' | 'customer_endpoint_routing_inconsistent' | 'unused_connector_alias' | 'arg_mismatch' | 'agent_guide_invalid' | 'agent_guide_duplicate_workflow' | 'agent_guide_duplicate_example' | 'agent_guide_example_workflow_missing' | 'agent_guide_capability_missing' | 'agent_guide_capability_kind' | 'app_package_sensitive_content';
4
+ export type CompileErrorCode = 'invalid_context_provider' | 'yaml_parse_error' | 'invalid_shape' | 'invalid_name' | 'duplicate_name' | 'reserved_name' | 'unsupported_manifest_version' | 'reserved_for_future_version' | 'invalid_operation_ref' | 'external_ref' | 'invalid_schema_ref' | 'unknown_schema_ref' | 'schema_ref_conflict' | 'invalid_expression' | 'expr_unknown_root' | 'expr_root_unavailable' | 'expr_operator_not_allowed' | 'expr_if_not_boolean' | 'unknown_step_ref' | 'forward_step_ref' | 'self_step_ref' | 'duplicate_step_id' | 'invalid_fulfilment' | 'invalid_elicitation_schema' | 'invalid_elicitation_flow' | 'invalid_confirmation_flow' | 'arg_type_mismatch' | 'ambient_context_action' | 'duplicate_resource' | 'duplicate_prompt' | 'duplicate_resource_uri' | 'unsupported_uri_template' | 'duplicate_widget' | 'unknown_widget_tool' | 'unknown_widget_action_tool' | 'duplicate_widget_tool' | 'invalid_widget_binding' | 'invalid_widget_state_handle' | 'widget_html_too_large' | 'widget_html_total_too_large' | 'invalid_asset' | 'invalid_capability_requirement' | 'state_secret_field' | 'invalid_knowledge' | 'knowledge_unhashed' | 'invalid_managed_collection' | 'invalid_variable_declaration' | 'invalid_managed_collection_source' | 'unknown_connector_alias' | 'connector_not_in_catalog' | 'unknown_operation' | 'connector_binding_required' | 'ambiguous_nested_connector_binding' | 'invalid_connector_call_graph' | 'unsupported_credential_profile' | 'credential_scope_mismatch' | 'credential_audience_mismatch' | 'customer_endpoint_auth_required' | 'customer_endpoint_mapping_required' | 'customer_endpoint_unknown_mapping' | 'customer_endpoint_bridge_unsupported' | 'assistant_messaging_unsupported' | 'assistant_capability_unknown' | 'assistant_public_user_reference' | 'assistant_public_effect_unconfirmed' | 'tool_anonymous_requires_identity' | 'interaction_action_invalid' | 'interaction_field_unknown' | 'interaction_field_control_mismatch' | 'interaction_field_missing' | 'interaction_initial_value_unknown' | 'interaction_initial_value_private' | 'interaction_consent_invalid' | 'interaction_expiry_invalid' | 'channel_dependency_missing' | 'channel_requirement_unsupported' | 'customer_endpoint_action_unsupported' | 'customer_endpoint_surface_unsupported' | 'customer_endpoint_credential_source_unsupported' | 'customer_endpoint_policy_conflict' | 'customer_endpoint_routing_inconsistent' | 'unused_connector_alias' | 'arg_mismatch' | 'agent_guide_invalid' | 'agent_guide_duplicate_workflow' | 'agent_guide_duplicate_example' | 'agent_guide_example_workflow_missing' | 'agent_guide_capability_missing' | 'agent_guide_capability_kind' | 'app_package_sensitive_content';
5
5
  export interface CompileError {
6
6
  readonly code: CompileErrorCode;
7
7
  /** Dotted path to the offending location (e.g. `tools.1.name`); empty string for the document root. */
@@ -101,6 +101,13 @@ function validateCollect(interaction, opener, byName, path, errors) {
101
101
  message: `initial value "${target}" is not an input of action "${action.name}"`,
102
102
  });
103
103
  }
104
+ else if (interaction.fields.some((field) => field.key === target && field.private === true)) {
105
+ errors.push({
106
+ code: 'interaction_initial_value_private',
107
+ path: valuePath,
108
+ message: `private field "${target}" is collected by the platform and cannot be seeded from the opener's output`,
109
+ });
110
+ }
104
111
  else {
105
112
  covered.add(target);
106
113
  }
@@ -41,7 +41,7 @@
41
41
  "@noodle-borg/managed-capabilities": "0.0.0",
42
42
  "@modelcontextprotocol/sdk": "^1.29.0",
43
43
  "@noodle-borg/admission-limits": "0.0.0",
44
- "@noodle-borg/agent-kit": "0.113.0",
44
+ "@noodle-borg/agent-kit": "0.113.1",
45
45
  "@noodle-borg/app-package": "0.0.0",
46
46
  "@noodle-borg/assistant-gateway": "0.0.0",
47
47
  "@noodle-borg/auth": "0.0.0",
@@ -124,6 +124,9 @@ export function createMcpRouter(lookup, options = {}) {
124
124
  ...(route?.kind === 'tenant' && route.publicResourceUrl !== undefined
125
125
  ? { publicResourceUrl: route.publicResourceUrl }
126
126
  : {}),
127
+ ...(route?.kind === 'tenant' && route.clientAddress !== undefined
128
+ ? { clientAddress: route.clientAddress }
129
+ : {}),
127
130
  }, routeId, maxBody, options.allowedOrigins, tenant);
128
131
  })()).then(() => logRequest(logger, logId, req, res, start));
129
132
  };
@@ -10,6 +10,8 @@ type ParsedRoute = {
10
10
  readonly ref: TenantRouteRef;
11
11
  readonly logId: string;
12
12
  readonly publicResourceUrl?: string;
13
+ /** The caller address the edge Worker observed; present only on edge-authenticated routes. */
14
+ readonly clientAddress?: string;
13
15
  } | {
14
16
  readonly kind: 'deployment';
15
17
  readonly deploymentId: string;
@@ -15,6 +15,7 @@ export async function resolveRoute(req, pathname, publicTenantRouting) {
15
15
  const ref = await publicTenantRouting.resolveTenant(publicRef);
16
16
  if (ref === undefined)
17
17
  return { ok: true, route: null };
18
+ const clientAddress = header(req, 'x-noodle-client-address');
18
19
  return {
19
20
  ok: true,
20
21
  route: {
@@ -22,6 +23,7 @@ export async function resolveRoute(req, pathname, publicTenantRouting) {
22
23
  ref,
23
24
  logId: tenantLogId(ref),
24
25
  publicResourceUrl: canonicalPublicResourceUrl(forwardedHost),
26
+ ...(clientAddress !== undefined ? { clientAddress } : {}),
25
27
  },
26
28
  };
27
29
  }
@@ -1,5 +1,5 @@
1
1
  import { randomUUID } from 'node:crypto';
2
- import { trustedPublicAdmission } from '@noodle-borg/admission-limits/portable';
2
+ import { clientAddressBucket, trustedPublicAdmission, } from '@noodle-borg/admission-limits/portable';
3
3
  import { createDualEraMcpHandler, handleStatelessHttp, JSON_RPC, } from '@noodle-borg/protocol';
4
4
  import { admissionContexts, requestsInvocationContext } from './admission-context.js';
5
5
  import { authorizeIdentityMode, authorizeMixedMode, authorizePublicServiceMode, canonicalResourceUrl, isIdentityMode, } from './identity-authorization.js';
@@ -134,6 +134,7 @@ export async function serveRequest(req, res, target, auth, routeId, maxBody, all
134
134
  ...(auth.accessMode !== undefined ? { accessMode: auth.accessMode } : {}),
135
135
  ...(req.socket.remoteAddress !== undefined ? { remoteAddress: req.socket.remoteAddress } : {}),
136
136
  });
137
+ const callerNetwork = clientAddressBucket(auth.clientAddress);
137
138
  for (const context of contexts) {
138
139
  const decision = auth.admissionGate
139
140
  ? await auth.admissionGate(context)
@@ -148,6 +149,7 @@ export async function serveRequest(req, res, target, auth, routeId, maxBody, all
148
149
  ...(context.env !== undefined ? { env: context.env } : {}),
149
150
  ...(context.serverVersion !== undefined ? { serverVersion: context.serverVersion } : {}),
150
151
  ...(context.accessMode !== undefined ? { accessMode: context.accessMode } : {}),
152
+ ...(callerNetwork !== undefined ? { callerNetwork } : {}),
151
153
  decision: decision.allow ? 'allow' : 'deny',
152
154
  ...(decision.reason !== undefined ? { reason: decision.reason } : {}),
153
155
  });
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noodleseed/assistant",
3
- "version": "1.38.0",
3
+ "version": "1.39.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.189.0",
3
+ "version": "0.190.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",
@@ -236,7 +236,7 @@
236
236
  "@modelcontextprotocol/client": "2.0.0",
237
237
  "@modelcontextprotocol/server": "2.0.0",
238
238
  "@noodle-borg/admission-limits": "0.0.0",
239
- "@noodle-borg/agent-kit": "0.113.0",
239
+ "@noodle-borg/agent-kit": "0.113.1",
240
240
  "@noodle-borg/app-audit": "0.0.0",
241
241
  "@noodle-borg/app-package": "0.0.0",
242
242
  "@noodle-borg/assistant-gateway": "0.0.0",