@noodleseed/one 0.169.0 → 0.170.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.
Files changed (109) hide show
  1. package/dist/cli.d.ts.map +1 -1
  2. package/dist/cli.js +3 -0
  3. package/dist/cli.js.map +1 -1
  4. package/dist/commands/capabilities.d.ts +19 -0
  5. package/dist/commands/capabilities.d.ts.map +1 -0
  6. package/dist/commands/capabilities.js +128 -0
  7. package/dist/commands/capabilities.js.map +1 -0
  8. package/dist/index.d.ts +1 -1
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +1 -1
  11. package/dist/index.js.map +1 -1
  12. package/dist/plugin-mode/plugin-operation-contract.d.ts +2 -2
  13. package/node_modules/@noodle-borg/agent-kit/dist/curated/command-groups.js +4 -0
  14. package/node_modules/@noodle-borg/agent-kit/dist/generated/example-files.js +1 -1
  15. package/node_modules/@noodle-borg/agent-kit/dist/generated/surface.js +2 -0
  16. package/node_modules/@noodle-borg/agent-kit/dist/skill-authoring-refs.js +3 -2
  17. package/node_modules/@noodle-borg/agent-kit/package.json +1 -1
  18. package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-interactive.d.ts +1 -0
  19. package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-interactive.js +4 -1
  20. package/node_modules/@noodle-borg/authoring/dist/assistant.d.ts +2 -2
  21. package/node_modules/@noodle-borg/authoring/dist/assistant.js +3 -1
  22. package/node_modules/@noodle-borg/authoring/dist/index.d.ts +1 -0
  23. package/node_modules/@noodle-borg/authoring/dist/index.js +1 -0
  24. package/node_modules/@noodle-borg/authoring/dist/load-authored.js +1 -1
  25. package/node_modules/@noodle-borg/authoring/dist/recording.d.ts +2 -1
  26. package/node_modules/@noodle-borg/authoring/dist/recording.js +29 -1
  27. package/node_modules/@noodle-borg/authoring/dist/server.d.ts +3 -0
  28. package/node_modules/@noodle-borg/authoring/dist/server.js +5 -1
  29. package/node_modules/@noodle-borg/authoring/dist/web-capabilities.d.ts +17 -0
  30. package/node_modules/@noodle-borg/authoring/dist/web-capabilities.js +15 -0
  31. package/node_modules/@noodle-borg/authoring/package.json +1 -0
  32. package/node_modules/@noodle-borg/capabilities/dist/index.js +7 -0
  33. package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-hosted-observability.js +102 -0
  34. package/node_modules/@noodle-borg/compiler/dist/artifact/assemble.js +3 -0
  35. package/node_modules/@noodle-borg/compiler/dist/artifact/types.d.ts +2 -0
  36. package/node_modules/@noodle-borg/compiler/dist/artifact/version.d.ts +2 -1
  37. package/node_modules/@noodle-borg/compiler/dist/artifact/version.js +2 -1
  38. package/node_modules/@noodle-borg/compiler/dist/compile.js +2 -0
  39. package/node_modules/@noodle-borg/compiler/dist/fulfilment-emit.js +18 -3
  40. package/node_modules/@noodle-borg/compiler/dist/manifest/schema.d.ts +34 -0
  41. package/node_modules/@noodle-borg/compiler/dist/manifest/schema.js +9 -2
  42. package/node_modules/@noodle-borg/compiler/dist/web-capabilities.js +55 -0
  43. package/node_modules/@noodle-borg/compiler/package.json +1 -0
  44. package/node_modules/@noodle-borg/connector-http/dist/ssrf.js +5 -0
  45. package/node_modules/@noodle-borg/knowledge-crawl/dist/bounded-body.js +38 -0
  46. package/node_modules/@noodle-borg/knowledge-crawl/dist/first-party.js +2 -3
  47. package/node_modules/@noodle-borg/knowledge-crawl/dist/html-text.js +10 -2
  48. package/node_modules/@noodle-borg/knowledge-crawl/dist/index.d.ts +1 -0
  49. package/node_modules/@noodle-borg/knowledge-crawl/dist/index.js +1 -0
  50. package/node_modules/@noodle-borg/knowledge-crawl/dist/page-reader.d.ts +26 -0
  51. package/node_modules/@noodle-borg/knowledge-crawl/dist/page-reader.js +127 -0
  52. package/node_modules/@noodle-borg/knowledge-crawl/dist/robots.js +48 -23
  53. package/node_modules/@noodle-borg/knowledge-crawl/package.json +1 -0
  54. package/node_modules/@noodle-borg/managed-capabilities/dist/budget.d.ts +29 -0
  55. package/node_modules/@noodle-borg/managed-capabilities/dist/budget.js +124 -0
  56. package/node_modules/@noodle-borg/managed-capabilities/dist/contracts.d.ts +212 -0
  57. package/node_modules/@noodle-borg/managed-capabilities/dist/contracts.js +113 -0
  58. package/node_modules/@noodle-borg/managed-capabilities/dist/errors.d.ts +8 -0
  59. package/node_modules/@noodle-borg/managed-capabilities/dist/errors.js +21 -0
  60. package/node_modules/@noodle-borg/managed-capabilities/dist/executor.d.ts +26 -0
  61. package/node_modules/@noodle-borg/managed-capabilities/dist/executor.js +156 -0
  62. package/node_modules/@noodle-borg/managed-capabilities/dist/limits.d.ts +15 -0
  63. package/node_modules/@noodle-borg/managed-capabilities/dist/limits.js +15 -0
  64. package/node_modules/@noodle-borg/managed-capabilities/dist/operator-contracts.d.ts +159 -0
  65. package/node_modules/@noodle-borg/managed-capabilities/dist/operator-contracts.js +69 -0
  66. package/node_modules/@noodle-borg/managed-capabilities/dist/operator-route.d.ts +5 -0
  67. package/node_modules/@noodle-borg/managed-capabilities/dist/operator-route.js +160 -0
  68. package/node_modules/@noodle-borg/managed-capabilities/dist/policy-store.d.ts +34 -0
  69. package/node_modules/@noodle-borg/managed-capabilities/dist/policy-store.js +61 -0
  70. package/node_modules/@noodle-borg/managed-capabilities/dist/portable.d.ts +10 -0
  71. package/node_modules/@noodle-borg/managed-capabilities/dist/portable.js +10 -0
  72. package/node_modules/@noodle-borg/managed-capabilities/dist/service.d.ts +83 -0
  73. package/node_modules/@noodle-borg/managed-capabilities/dist/service.js +139 -0
  74. package/node_modules/@noodle-borg/managed-capabilities/dist/urls.d.ts +3 -0
  75. package/node_modules/@noodle-borg/managed-capabilities/dist/urls.js +30 -0
  76. package/node_modules/@noodle-borg/managed-capabilities/package.json +49 -0
  77. package/node_modules/@noodle-borg/module/dist/contract.d.ts +11 -0
  78. package/node_modules/@noodle-borg/runtime/dist/confirmation.js +29 -0
  79. package/node_modules/@noodle-borg/runtime/dist/connector/types.d.ts +2 -0
  80. package/node_modules/@noodle-borg/runtime/dist/execute.d.ts +3 -0
  81. package/node_modules/@noodle-borg/runtime/dist/execute.js +6 -1
  82. package/node_modules/@noodle-borg/runtime/dist/index.d.ts +2 -1
  83. package/node_modules/@noodle-borg/runtime/dist/index.js +2 -1
  84. package/node_modules/@noodle-borg/runtime/dist/interactive.js +10 -1
  85. package/node_modules/@noodle-borg/runtime/dist/operation-execution.js +3 -0
  86. package/node_modules/@noodle-borg/runtime/dist/result-meta.d.ts +2 -0
  87. package/node_modules/@noodle-borg/runtime/dist/result-meta.js +6 -0
  88. package/node_modules/@noodle-borg/runtime/dist/result.d.ts +4 -0
  89. package/node_modules/@noodle-borg/runtime/dist/web-capabilities.d.ts +71 -0
  90. package/node_modules/@noodle-borg/runtime/dist/web-capabilities.js +41 -0
  91. package/node_modules/@noodle-borg/runtime/package.json +1 -0
  92. package/node_modules/@noodle-borg/service/dist/local-options.d.ts +1 -0
  93. package/node_modules/@noodle-borg/service/dist/local-web-capabilities.js +13 -0
  94. package/node_modules/@noodle-borg/service/dist/mcp-protocol-runtime.js +21 -0
  95. package/node_modules/@noodle-borg/service/dist/modules/route-dispatch.js +13 -0
  96. package/node_modules/@noodle-borg/service/dist/registry-compile.js +3 -0
  97. package/node_modules/@noodle-borg/service/dist/registry-types.d.ts +1 -0
  98. package/node_modules/@noodle-borg/service/dist/registry.js +3 -0
  99. package/node_modules/@noodle-borg/service/dist/routes/assistant-agent.js +5 -2
  100. package/node_modules/@noodle-borg/service/dist/routes/assistant-interactions.js +7 -4
  101. package/node_modules/@noodle-borg/service/dist/serve-local.js +14 -0
  102. package/node_modules/@noodle-borg/service/dist/serve-resource-auth.js +10 -0
  103. package/node_modules/@noodle-borg/service/dist/service.js +7 -1
  104. package/node_modules/@noodle-borg/service/dist/web-capabilities.js +39 -0
  105. package/node_modules/@noodle-borg/service/package.json +3 -1
  106. package/node_modules/@noodle-borg/wire-contracts/dist/index.d.ts +1 -0
  107. package/node_modules/@noodle-borg/wire-contracts/dist/index.js +1 -0
  108. package/node_modules/@noodle-borg/wire-contracts/package.json +1 -0
  109. package/package.json +3 -2
@@ -1,4 +1,5 @@
1
1
  import type { CredentialProfile, OperationSignature, ResolvedOperationRef } from '@noodle-borg/compiler';
2
+ import type { CapabilityBudget } from '@noodle-borg/managed-capabilities';
2
3
  import type { DownstreamCredential } from '../broker/types.js';
3
4
  import type { CustomerConnectorRoute } from '../customer-routing.js';
4
5
  import type { OperationCoordinationDeclaration, OperationCoordinationSnapshot } from '../operation-coordination.js';
@@ -81,6 +82,7 @@ export interface ConnectorCallHost {
81
82
  }
82
83
  /** A single connector-operation invocation, fully resolved and credentialed by the runtime. */
83
84
  export interface ConnectorCall {
85
+ readonly capabilityBudget?: CapabilityBudget;
84
86
  readonly operation: string;
85
87
  /** Runtime-generated, deployment/step-bound identity. Not a business input or recovery authority. */
86
88
  readonly execution?: Readonly<{
@@ -1,4 +1,5 @@
1
1
  import type { ArtifactFulfilment, RuntimeArtifact } from '@noodle-borg/compiler';
2
+ import { CapabilityBudget } from '@noodle-borg/managed-capabilities';
2
3
  import type { CredentialBroker } from './broker/types.js';
3
4
  import type { CallerIdentity, ConnectorRegistry, ExecutionTraceSink } from './connector/types.js';
4
5
  import type { FrozenCustomerRoutes } from './customer-routing.js';
@@ -18,6 +19,8 @@ export { evalExprMap, validateAgainstSchema, validateAgainstSchemaWithDefaults,
18
19
  * [ADR 0005](../../../docs/decisions/0005-runtime-execution-boundary.md)).
19
20
  */
20
21
  export interface ExecuteDeps {
22
+ /** Trusted shared assistant-turn / MCP-invocation budget; never part of the expression scope. */
23
+ readonly capabilityBudget?: CapabilityBudget;
21
24
  readonly connectors: ConnectorRegistry;
22
25
  readonly broker: CredentialBroker;
23
26
  readonly policy?: PolicyGate;
@@ -1,3 +1,4 @@
1
+ import { CapabilityBudget } from '@noodle-borg/managed-capabilities';
1
2
  import { resolveVariableEnvironment } from './business-variables.js';
2
3
  import { preflightFulfilmentSignatures } from './connector-snapshot.js';
3
4
  import { preflightFulfilmentCustomerRoutes } from './customer-routing.js';
@@ -29,7 +30,11 @@ export async function executeTool(artifact, toolName, input, deps) {
29
30
  const variables = resolveVariableEnvironment(artifact.server.variables ?? [], await resolveEnv(deps), toolName);
30
31
  if (!variables.ok)
31
32
  return variables;
32
- return runFulfilment(tool.fulfilment, input, toolName, { ...deps, env: variables.env }, deps.beforeDispatch);
33
+ return runFulfilment(tool.fulfilment, input, toolName, {
34
+ ...deps,
35
+ env: variables.env,
36
+ capabilityBudget: deps.capabilityBudget ?? new CapabilityBudget(),
37
+ }, deps.beforeDispatch);
33
38
  }
34
39
  /**
35
40
  * Execute a resource read against a resolved artifact. `input` is the resource's variable scope — the
@@ -20,8 +20,9 @@ export type { OperationEvidence, OperationEvidenceIntent, OperationEvidencePort,
20
20
  export { AllowAllPolicy } from './policy/allow-all.js';
21
21
  export type { PolicyContext, PolicyDecision, PolicyGate } from './policy/types.js';
22
22
  export { type ConfirmationActionReview, type ConfirmationPreparationResult, type ConfirmationReview, type ConnectorFailureAttribution, type ElicitationRequest, type ElicitationResponse, type ExecutionError, type ExecutionErrorCode, type ExecutionResult, type InteractiveExecutionResult, isConfirmationRequired, isInputRequired, isInputRequiredForConfirmation, type PreparedOperationAction, type PreparedToolContinuation, type ToolContinuation, type ToolPreparationContinuation, } from './result.js';
23
- export { splitResultMeta } from './result-meta.js';
23
+ export { hasEphemeralEvidence, splitResultMeta } from './result-meta.js';
24
24
  export { type CallerStateAdoptionInput, type CallerStateAdoptionResult, claimableStateHandleNames, } from './state-handle-ownership.js';
25
25
  export { assertExpectedStateRevision, assertNoSecretValue, assertSchemaValue, assertStateHandleNotCompleted, COMPLETE_STATE_OPERATION, createMutableStateHandleRecord, createStateConnector, InMemoryStateHandleStore, type MutableStateHandleRecord, PATCH_STATE_OPERATION, READ_STATE_OPERATION, STATE_CONNECTOR_ID, STATE_CONNECTOR_VERSION, STATE_OPERATION_SIGNATURES, StateConnector, type StateHandleRecord, type StateHandleStore, type StateInput, type StateMutationInput, type StatePatchInput, stateHandleRecordForMutation, toPublicStateHandleRecord, } from './state-handles.js';
26
26
  export type { ToolDispatchContext, ToolDispatchDecision, ToolDispatchHook, } from './tool-dispatch.js';
27
+ export { WebCapabilityConnector, type WebCapabilityExecutionPort } from './web-capabilities.js';
27
28
  //# sourceMappingURL=index.d.ts.map
@@ -15,7 +15,8 @@ export { executeToolInteractive, resumeTool } from './interactive.js';
15
15
  export { resolveManagedOrigins, } from './managed-origins.js';
16
16
  export { AllowAllPolicy } from './policy/allow-all.js';
17
17
  export { isConfirmationRequired, isInputRequired, isInputRequiredForConfirmation, } from './result.js';
18
- export { splitResultMeta } from './result-meta.js';
18
+ export { hasEphemeralEvidence, splitResultMeta } from './result-meta.js';
19
19
  export { claimableStateHandleNames, } from './state-handle-ownership.js';
20
20
  export { assertExpectedStateRevision, assertNoSecretValue, assertSchemaValue, assertStateHandleNotCompleted, COMPLETE_STATE_OPERATION, createMutableStateHandleRecord, createStateConnector, InMemoryStateHandleStore, PATCH_STATE_OPERATION, READ_STATE_OPERATION, STATE_CONNECTOR_ID, STATE_CONNECTOR_VERSION, STATE_OPERATION_SIGNATURES, StateConnector, stateHandleRecordForMutation, toPublicStateHandleRecord, } from './state-handles.js';
21
+ export { WebCapabilityConnector } from './web-capabilities.js';
21
22
  //# sourceMappingURL=index.js.map
@@ -1,3 +1,4 @@
1
+ import { CapabilityBudget } from '@noodle-borg/managed-capabilities';
1
2
  import { resolveVariableEnvironment, validateVariableContinuation } from './business-variables.js';
2
3
  import { preflightFulfilmentCustomerRoutes } from './customer-routing.js';
3
4
  import { validateElicitationContent } from './elicitation-response.js';
@@ -17,7 +18,11 @@ export async function executeToolInteractive(artifact, toolName, input, deps) {
17
18
  const variables = resolveVariableEnvironment(artifact.server.variables ?? [], await resolveEnv(deps), toolName);
18
19
  if (!variables.ok)
19
20
  return { status: 'failed', error: variables.error };
20
- deps = { ...deps, env: variables.env };
21
+ deps = {
22
+ ...deps,
23
+ env: variables.env,
24
+ capabilityBudget: deps.capabilityBudget ?? new CapabilityBudget(),
25
+ };
21
26
  if (tool.fulfilment.kind !== 'flow' || !tool.fulfilment.steps.some((s) => s.kind === 'elicit')) {
22
27
  return toInteractive(await runFulfilment(tool.fulfilment, input, toolName, deps, deps.beforeDispatch));
23
28
  }
@@ -32,6 +37,7 @@ export async function executeToolInteractive(artifact, toolName, input, deps) {
32
37
  }
33
38
  /** Resume one server-held continuation with the user's reviewed response. */
34
39
  export async function resumeTool(artifact, continuation, response, deps) {
40
+ deps = { ...deps, capabilityBudget: new CapabilityBudget(continuation.capabilityBudget) };
35
41
  if (!sameArtifact(artifact, continuation) || continuation.version !== 1) {
36
42
  return interactiveFail('invalid_continuation', 'tool continuation does not match the artifact');
37
43
  }
@@ -84,6 +90,9 @@ async function runInteractiveFlow(artifact, toolName, flow, input, startIndex, s
84
90
  status: 'input_required',
85
91
  request,
86
92
  continuation: {
93
+ ...(deps.capabilityBudget === undefined
94
+ ? {}
95
+ : { capabilityBudget: deps.capabilityBudget.snapshot() }),
87
96
  version: 1,
88
97
  artifact: artifactIdentity(artifact),
89
98
  toolName,
@@ -224,6 +224,9 @@ async function invokeOperation(ref, args, sig, toolName, deps, policy, host, env
224
224
  if (signal?.aborted)
225
225
  return fail('execution_cancelled', 'Execution deadline elapsed before connector dispatch.');
226
226
  output = await connector.invoke({
227
+ ...(deps.capabilityBudget === undefined
228
+ ? {}
229
+ : { capabilityBudget: deps.capabilityBudget }),
227
230
  operation: ref.operation,
228
231
  execution,
229
232
  reportOutcome: (value) => {
@@ -1,3 +1,5 @@
1
+ /** Ephemeral extraction evidence is usable in the current turn but never replay/persistence data. */
2
+ export declare function hasEphemeralEvidence(output: unknown): boolean;
1
3
  /** @internal Shared with suspension-aware execution and surface adapters. */
2
4
  export declare function splitResultMeta(output: unknown): {
3
5
  readonly visible: unknown;
@@ -1,4 +1,8 @@
1
1
  const RESULT_META_KEY = '__noodleResultMeta';
2
+ /** Ephemeral extraction evidence is usable in the current turn but never replay/persistence data. */
3
+ export function hasEphemeralEvidence(output) {
4
+ return splitResultMeta(output).meta?.['noodle/ephemeralEvidence'] === true;
5
+ }
2
6
  /** @internal Shared with suspension-aware execution and surface adapters. */
3
7
  export function splitResultMeta(output) {
4
8
  if (output === null || typeof output !== 'object' || Array.isArray(output)) {
@@ -31,6 +35,8 @@ export function attachResultMeta(output, metas) {
31
35
  }
32
36
  function mergeRecords(target, source) {
33
37
  for (const [key, value] of Object.entries(source)) {
38
+ if (key === 'noodle/ephemeralEvidence' && target[key] === true)
39
+ continue;
34
40
  const existing = target[key];
35
41
  if (isPlainRecord(existing) && isPlainRecord(value)) {
36
42
  mergeRecords(existing, value);
@@ -1,4 +1,5 @@
1
1
  import type { CredentialProfile } from '@noodle-borg/compiler';
2
+ import type { CapabilityBudgetSnapshot } from '@noodle-borg/managed-capabilities';
2
3
  import type { ConnectorFailureCategory } from './connector/types.js';
3
4
  import type { CustomerRouteBinding } from './customer-routing.js';
4
5
  /** Why a tool call could not be fulfilled. Protocol and embedded adapters map this internal contract. */
@@ -60,6 +61,7 @@ export type ElicitationResponse = {
60
61
  * never be serialized into MCP or embedded-assistant client payloads.
61
62
  */
62
63
  export interface ToolContinuation {
64
+ readonly capabilityBudget?: CapabilityBudgetSnapshot;
63
65
  readonly version: 1;
64
66
  readonly artifact: {
65
67
  readonly manifestName: string;
@@ -86,6 +88,7 @@ interface ContinuationArtifactIdentity {
86
88
  * can evaluate pure maps and request more input, but cannot execute a connector operation.
87
89
  */
88
90
  export interface ToolPreparationContinuation {
91
+ readonly capabilityBudget?: CapabilityBudgetSnapshot;
89
92
  readonly kind: 'confirmation_preparation';
90
93
  readonly version: 1;
91
94
  readonly artifact: ContinuationArtifactIdentity;
@@ -102,6 +105,7 @@ export interface ToolPreparationContinuation {
102
105
  * behind an opaque interaction id and release it to {@code executePreparedTool} only after approval.
103
106
  */
104
107
  export interface PreparedToolContinuation {
108
+ readonly capabilityBudget?: CapabilityBudgetSnapshot;
105
109
  readonly kind: 'prepared_confirmation';
106
110
  /** Private hosting snapshot; never projected into a model-visible confirmation. */
107
111
  readonly executionRevision?: string;
@@ -0,0 +1,71 @@
1
+ import type { WebCapability, WebExtractResult } from '@noodle-borg/managed-capabilities';
2
+ import { type Connector, type ConnectorCall } from './connector/types.js';
3
+ export type WebCapabilityExecutionPort = (declaration: WebCapability, request: unknown, call: ConnectorCall) => Promise<WebExtractResult>;
4
+ /** Thin ordinary connector; deployment binding and policy authority are injected by the service. */
5
+ export declare class WebCapabilityConnector implements Connector {
6
+ private readonly declarations;
7
+ private readonly execute;
8
+ readonly id = "noodle_web";
9
+ readonly version = "1.0.0";
10
+ constructor(declarations: readonly WebCapability[], execute: WebCapabilityExecutionPort);
11
+ signature(operation: string): {
12
+ type: "read";
13
+ input: import("zod/v4/core").ZodStandardJSONSchemaPayload<import("zod").ZodObject<{
14
+ name: import("zod").ZodString;
15
+ request: import("zod").ZodObject<{
16
+ urls: import("zod").ZodArray<import("zod").ZodString>;
17
+ domains: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
18
+ }, import("zod/v4/core").$strict>;
19
+ }, import("zod/v4/core").$strict>>;
20
+ output: import("zod/v4/core").ZodStandardJSONSchemaPayload<import("zod").ZodObject<{
21
+ status: import("zod").ZodEnum<{
22
+ complete: "complete";
23
+ partial: "partial";
24
+ }>;
25
+ items: import("zod").ZodArray<import("zod").ZodObject<{
26
+ requestIndex: import("zod").ZodNumber;
27
+ sourceRef: import("zod").ZodString;
28
+ content: import("zod").ZodObject<{
29
+ format: import("zod").ZodLiteral<"text">;
30
+ text: import("zod").ZodString;
31
+ }, import("zod/v4/core").$strict>;
32
+ links: import("zod").ZodArray<import("zod").ZodObject<{
33
+ url: import("zod").ZodString;
34
+ label: import("zod").ZodOptional<import("zod").ZodString>;
35
+ }, import("zod/v4/core").$strict>>;
36
+ truncated: import("zod").ZodBoolean;
37
+ }, import("zod/v4/core").$strict>>;
38
+ sources: import("zod").ZodArray<import("zod").ZodObject<{
39
+ ref: import("zod").ZodString;
40
+ url: import("zod").ZodString;
41
+ title: import("zod").ZodOptional<import("zod").ZodString>;
42
+ retrievedAt: import("zod").ZodISODateTime;
43
+ publishedAt: import("zod").ZodOptional<import("zod").ZodISODateTime>;
44
+ observedAt: import("zod").ZodOptional<import("zod").ZodISODateTime>;
45
+ expiresAt: import("zod").ZodOptional<import("zod").ZodISODateTime>;
46
+ attribution: import("zod").ZodOptional<import("zod").ZodString>;
47
+ rights: import("zod").ZodOptional<import("zod").ZodString>;
48
+ }, import("zod/v4/core").$strict>>;
49
+ warnings: import("zod").ZodArray<import("zod").ZodObject<{
50
+ requestIndex: import("zod").ZodNumber;
51
+ code: import("zod").ZodEnum<{
52
+ capability_unavailable: "capability_unavailable";
53
+ capability_binding_invalid: "capability_binding_invalid";
54
+ capability_requirement_unsupported: "capability_requirement_unsupported";
55
+ capability_policy_denied: "capability_policy_denied";
56
+ capability_budget_exhausted: "capability_budget_exhausted";
57
+ capability_source_rejected: "capability_source_rejected";
58
+ capability_provider_failed: "capability_provider_failed";
59
+ capability_result_invalid: "capability_result_invalid";
60
+ capability_cancelled: "capability_cancelled";
61
+ content_truncated: "content_truncated";
62
+ }>;
63
+ }, import("zod/v4/core").$strict>>;
64
+ }, import("zod/v4/core").$strict>>;
65
+ } | undefined;
66
+ executionBoundMs(): number;
67
+ invoke(call: ConnectorCall): Promise<WebExtractResult & {
68
+ readonly __noodleResultMeta: Readonly<Record<string, unknown>>;
69
+ }>;
70
+ }
71
+ //# sourceMappingURL=web-capabilities.d.ts.map
@@ -0,0 +1,41 @@
1
+ import { CapabilityError, WEB_CONNECTOR_ID, WEB_CONNECTOR_VERSION, WEB_OPERATION_SIGNATURE, webOperationInputSchema, } from '@noodle-borg/managed-capabilities';
2
+ import { ConnectorInvocationError } from './connector/types.js';
3
+ /** Thin ordinary connector; deployment binding and policy authority are injected by the service. */
4
+ export class WebCapabilityConnector {
5
+ declarations;
6
+ execute;
7
+ id = WEB_CONNECTOR_ID;
8
+ version = WEB_CONNECTOR_VERSION;
9
+ constructor(declarations, execute) {
10
+ this.declarations = declarations;
11
+ this.execute = execute;
12
+ }
13
+ signature(operation) {
14
+ return operation === 'extract' ? WEB_OPERATION_SIGNATURE : undefined;
15
+ }
16
+ executionBoundMs() {
17
+ return 30_000;
18
+ }
19
+ async invoke(call) {
20
+ const input = webOperationInputSchema.safeParse(call.args);
21
+ const declaration = input.success
22
+ ? this.declarations.find((value) => value.name === input.data.name)
23
+ : undefined;
24
+ if (call.operation !== 'extract' ||
25
+ declaration === undefined ||
26
+ !input.success ||
27
+ call.capabilityBudget === undefined) {
28
+ throw new ConnectorInvocationError('capability_policy_denied', { retryable: false });
29
+ }
30
+ try {
31
+ return {
32
+ ...(await this.execute(declaration, input.data.request, call)),
33
+ __noodleResultMeta: { 'noodle/ephemeralEvidence': true },
34
+ };
35
+ }
36
+ catch (error) {
37
+ throw new ConnectorInvocationError(error instanceof CapabilityError ? error.code : 'capability_unavailable', { retryable: false });
38
+ }
39
+ }
40
+ }
41
+ //# sourceMappingURL=web-capabilities.js.map
@@ -26,6 +26,7 @@
26
26
  "typecheck": "tsc -p tsconfig.json --noEmit"
27
27
  },
28
28
  "dependencies": {
29
+ "@noodle-borg/managed-capabilities": "0.0.0",
29
30
  "@noodle-borg/compiler": "0.0.0",
30
31
  "@noodle-borg/module": "0.0.0"
31
32
  },
@@ -6,6 +6,7 @@ import type { LocalDevtoolsDelegatedExchangeRuntime } from './local-devtools-del
6
6
  import type { ServerRegistry } from './registry.js';
7
7
  import type { ConfigStore, TenantBridgeAuthConfig } from './store.js';
8
8
  type LocalRuntimeOptions = {
9
+ readonly capabilities?: import('@noodle-borg/managed-capabilities').CapabilityService;
9
10
  readonly assistantStore?: import('@noodle-borg/assistant-gateway/portable').AssistantStore;
10
11
  readonly assistantAppearance?: import('@noodle-borg/assistant-gateway/portable').AssistantAppearanceSettingsStore;
11
12
  readonly publicEmbeds?: import('@noodle-borg/assistant-gateway/portable').PublicEmbedStore;
@@ -0,0 +1,13 @@
1
+ import { InMemoryDailyCounterStore } from '@noodle-borg/admission-limits/portable';
2
+ import { PublicPageReader } from '@noodle-borg/knowledge-crawl';
3
+ import { CapabilityService, InMemoryCapabilityPolicyStore, } from '@noodle-borg/managed-capabilities';
4
+ /** Loopback-only composition. Keep PostgreSQL imports out of the published CLI graph. */
5
+ export function localWebCapabilities() {
6
+ return new CapabilityService({
7
+ profile: 'development',
8
+ policies: new InMemoryCapabilityPolicyStore(),
9
+ counters: new InMemoryDailyCounterStore(),
10
+ reader: new PublicPageReader(),
11
+ });
12
+ }
13
+ //# sourceMappingURL=local-web-capabilities.js.map
@@ -0,0 +1,21 @@
1
+ import { RequestStateManager, requestStateSecretBox, } from '@noodle-borg/protocol';
2
+ /**
3
+ * Build the fleet-shared request-state manager. Static-key deployments use an HKDF domain-separated key;
4
+ * KMS deployments reuse the configured envelope-encryption custodian because its raw KEK cannot be
5
+ * exported for HKDF.
6
+ */
7
+ export function createHostedMcpRequestStateManager(input) {
8
+ if (input.secretMasterKey !== undefined) {
9
+ return new RequestStateManager(requestStateSecretBox(Buffer.from(input.secretMasterKey, 'base64')));
10
+ }
11
+ return input.secretBox === undefined ? undefined : new RequestStateManager(input.secretBox);
12
+ }
13
+ /** Resolve the temporary origin-wide rollout gate from operator configuration. */
14
+ export function resolveMcpProtocolMode(value) {
15
+ if (value === undefined || value === 'dual')
16
+ return 'dual';
17
+ if (value === 'legacy-only')
18
+ return value;
19
+ throw new Error('NOODLE_MCP_PROTOCOL_MODE must be dual or legacy-only');
20
+ }
21
+ //# sourceMappingURL=mcp-protocol-runtime.js.map
@@ -14,6 +14,19 @@ export function createModuleRouteContext(hostRequest, deps) {
14
14
  logger: deps.logger ?? noopModuleLogger,
15
15
  controlPlane: deps.gate,
16
16
  audit: deps.audit,
17
+ capabilityDeployments: {
18
+ get: async (request, scope) => {
19
+ if (request !== hostRequest || !authorizedOrgs.has(scope.org))
20
+ return undefined;
21
+ const target = await deps.registry.getActiveByTenant(scope);
22
+ if (target?.deploymentId === undefined)
23
+ return undefined;
24
+ return {
25
+ deploymentId: target.deploymentId,
26
+ declarations: target.served.artifact.server.capabilities ?? [],
27
+ };
28
+ },
29
+ },
17
30
  platformIdentityRecovery: {
18
31
  reconcile: (plan) => deps.registry.reconcilePlatformAccountReset(plan),
19
32
  customerAuthRestoreProjections: async (deploymentIds) => (await deps.registry.customerAuthRestoreProjections(deploymentIds)).map((projection) => ({
@@ -14,6 +14,7 @@ import { missingCapabilityErrors, missingSecretErrors, missingVariableErrors, }
14
14
  import { servedTargetFor } from './registry-targets.js';
15
15
  import { createDeploymentStateConnector, } from './state-connector-factory.js';
16
16
  import { resolveConfigScope, } from './store.js';
17
+ import { deploymentWebConnector } from './web-capabilities.js';
17
18
  /** Reject unsupported persisted semantics before constructing executable runtime dependencies. */
18
19
  export async function compilePersistedRegistryRecord(record, compileTarget) {
19
20
  const versionError = deploymentRecordVersionError(record);
@@ -197,11 +198,13 @@ export async function compileRegistryTarget(context, input) {
197
198
  artifact,
198
199
  ...(boundDeploymentId === undefined ? {} : { deploymentId: boundDeploymentId }),
199
200
  });
201
+ const webConnector = deploymentWebConnector(artifact, tenant, boundDeploymentId, context.capabilities);
200
202
  return {
201
203
  artifact,
202
204
  deps: {
203
205
  connectors: new InMemoryConnectorRegistry([
204
206
  ...context.platformConnectors,
207
+ ...(webConnector === undefined ? [] : [webConnector]),
205
208
  ...(nativeRecords === undefined ? [] : [nativeRecords]),
206
209
  ...(stateConnector !== undefined ? [stateConnector] : []),
207
210
  ...httpConnectors,
@@ -96,6 +96,7 @@ export interface AccessUpdateOptions {
96
96
  readonly serverVersion?: string | undefined;
97
97
  }
98
98
  export interface ServerRegistryOptions {
99
+ readonly capabilities?: import('@noodle-borg/managed-capabilities').CapabilityService;
99
100
  readonly nativeRecords?: NativeRecordConnectorFactory;
100
101
  /** Pure renderer injection used for deployment-bound package construction and failure testing. */
101
102
  readonly renderAppPackage?: AppPackageRenderer;
@@ -32,6 +32,7 @@ export class ServerRegistry {
32
32
  #platformCatalog;
33
33
  #platformConnectors;
34
34
  #nativeRecords;
35
+ #capabilities;
35
36
  #stateHandleStoreFactory;
36
37
  #delegatedCredentialStore;
37
38
  #sealCustomerCredential;
@@ -61,6 +62,7 @@ export class ServerRegistry {
61
62
  this.#platformCatalog = withBuiltinStateCatalog(options.platformCatalog ?? []);
62
63
  this.#platformConnectors = options.platformConnectors ?? [];
63
64
  this.#nativeRecords = options.nativeRecords;
65
+ this.#capabilities = options.capabilities;
64
66
  this.#stateHandleStoreFactory = options.stateHandleStoreFactory;
65
67
  this.#delegatedCredentialStore = options.delegatedCredentialStore;
66
68
  this.#sealCustomerCredential = options.sealCustomerCredential;
@@ -311,6 +313,7 @@ export class ServerRegistry {
311
313
  stateHandleStoreFactory: this.#stateHandleStoreFactory,
312
314
  platformConnectors: this.#platformConnectors,
313
315
  nativeRecords: this.#nativeRecords,
316
+ capabilities: this.#capabilities,
314
317
  policyGate: this.#policyGate,
315
318
  appPackageRenderer: this.#appPackageRenderer,
316
319
  knowledgeSearch: this.#knowledgeSearch,
@@ -3,6 +3,7 @@ import { assistantCoreModelMessages, assistantTurnModelContextMessages, requestA
3
3
  import { assistantGuideModelContext, assistantModelToolOncePerSession, assistantModelToolRequiredWhenVisible, assistantOmittedToolResult, assistantViewAvailableData, dispatchAssistantTool, projectAssistantGuide, publicSurfaceOf, recoverableAssistantView, remainingTurnTokens, selectAssistantModelTools, toolTouchesDelegatedAuth, withAssistantSessionExecutionAuthority, } from '@noodle-borg/assistant-gateway/portable';
4
4
  import { validateJsonSchemaWithDefaults } from '@noodle-borg/compiler';
5
5
  import { guardedFetch } from '@noodle-borg/connector-http';
6
+ import { CapabilityBudget } from '@noodle-borg/managed-capabilities';
6
7
  import { evaluateToolAuthorization } from '@noodle-borg/protocol';
7
8
  import { interceptForElevation, offersSignIn } from './assistant-elevation.js';
8
9
  import { assistantKnowledgeModelTools, executeAssistantKnowledgeSearch, findAssistantKnowledgeComponent, KNOWLEDGE_CITATION_GUIDANCE, resolveAssistantKnowledge, } from './assistant-knowledge.js';
@@ -98,6 +99,7 @@ export async function runAgentTurn(target, session, message, context, deps, emit
98
99
  // Across every step of this turn, not per step: eight tool calls is eight, however the model splits
99
100
  // them, or a model that loops one call per step would spend the budget a step at a time.
100
101
  let toolCallsThisTurn = 0;
102
+ const capabilityBudget = new CapabilityBudget();
101
103
  let omittedToolRecoveries = 0;
102
104
  let remainingTokens = binding.requestPolicy?.maxTokensPerTurn;
103
105
  const turnSignal = binding.requestPolicy?.maxTurnMs === undefined
@@ -247,7 +249,7 @@ export async function runAgentTurn(target, session, message, context, deps, emit
247
249
  artifact: target.served.artifact,
248
250
  tool,
249
251
  arguments: args,
250
- executeDeps: withAssistantSessionExecutionAuthority(target.served.deps, target.served.artifact, session),
252
+ executeDeps: withAssistantSessionExecutionAuthority({ ...target.served.deps, capabilityBudget }, target.served.artifact, session),
251
253
  caller: session.caller,
252
254
  context,
253
255
  session,
@@ -273,7 +275,8 @@ export async function runAgentTurn(target, session, message, context, deps, emit
273
275
  arguments: args,
274
276
  }, (failure) => deps.logger?.warn('assistant.view.unresolved', { ...failure }));
275
277
  if (view) {
276
- await deps.store.replaceLatestView(session.id, recoverableAssistantView(view));
278
+ if (!dispatch.ephemeral)
279
+ await deps.store.replaceLatestView(session.id, recoverableAssistantView(view));
277
280
  emit({ event: 'view_available', data: { ...view } });
278
281
  }
279
282
  messages.push({
@@ -1,5 +1,5 @@
1
1
  import { AssistantInteractionCapacityError, assistantConfirmationReview, assistantConfirmationTransition, assistantInputTransition, assistantInteractionTool, assistantPreparedArgumentReview, assistantPreparedToolContinuation, assistantSafeOutput, assistantToolContinuation, assistantViewAvailableData, auditAssistantInteraction, boundedAssistantExecution, recoverableAssistantView, withAssistantSessionExecutionAuthority, } from '@noodle-borg/assistant-gateway/portable';
2
- import { executePreparedTool, executeToolInteractive, resumeTool, resumeToolPreparation, } from '@noodle-borg/runtime';
2
+ import { executePreparedTool, executeToolInteractive, hasEphemeralEvidence, resumeTool, resumeToolPreparation, } from '@noodle-borg/runtime';
3
3
  import { readJsonBody, sendJson } from '@noodle-borg/transport-http';
4
4
  import { applyBrowserCors, authenticateSession, now, } from './assistant.js';
5
5
  import { replayOrConflict, writeUnknownOutcome } from './assistant-interaction-replay.js';
@@ -347,7 +347,9 @@ async function finishExecution(res, deps, session, interaction, context, result,
347
347
  }
348
348
  const completedTool = target.served.artifact.tools.find((tool) => tool.name === toolName);
349
349
  const safeOutput = assistantSafeOutput(completedTool?.outputSchema, result.output);
350
- const completed = await completeAssistantInteractionExecution(deps, session, interaction, 'succeeded', 'tool_completed', toolName, { result: safeOutput });
350
+ const ephemeral = hasEphemeralEvidence(result.output);
351
+ const retainedOutput = ephemeral ? { evidenceRetained: false } : safeOutput;
352
+ const completed = await completeAssistantInteractionExecution(deps, session, interaction, 'succeeded', 'tool_completed', toolName, { result: retainedOutput });
351
353
  if (!completed)
352
354
  return writeUnknownOutcome(res, deps, session, interaction, 'accept');
353
355
  await auditAssistantInteraction({
@@ -364,7 +366,7 @@ async function finishExecution(res, deps, session, interaction, context, result,
364
366
  // Model-facing scaffolding: the panel saw the tool_completed card, never this row's tool JSON.
365
367
  {
366
368
  role: 'assistant',
367
- content: `Completed ${toolName}: ${JSON.stringify(safeOutput)}`,
369
+ content: `Completed ${toolName}: ${JSON.stringify(retainedOutput)}`,
368
370
  kind: 'narration',
369
371
  },
370
372
  ]);
@@ -377,7 +379,8 @@ async function finishExecution(res, deps, session, interaction, context, result,
377
379
  result: safeOutput,
378
380
  }, (failure) => deps.logger?.warn('assistant.view.unresolved', { ...failure }));
379
381
  if (view) {
380
- await deps.store.replaceLatestView(session.id, recoverableAssistantView(view));
382
+ if (!ephemeral)
383
+ await deps.store.replaceLatestView(session.id, recoverableAssistantView(view));
381
384
  writeViewAvailable(res, view);
382
385
  }
383
386
  await narrateResolvedInteraction(res, deps, target, session, toolName, 'accept', safeOutput, context, suggestions);
@@ -3,6 +3,7 @@ import { InMemoryControlPlaneStore } from '@noodle-borg/control-plane/portable';
3
3
  import { InMemoryAssetStore } from './assets.js';
4
4
  import { createCustomerVerifierFactory, createHostedCustomerVerifierFactory, createLocalDevtoolsCustomerVerifierFactory, } from './customer-verifier.js';
5
5
  import { createLocalDevtoolsDelegatedCredentialSource } from './local-devtools-delegated-credentials.js';
6
+ import { localWebCapabilities } from './local-web-capabilities.js';
6
7
  import { ServerRegistry } from './registry.js';
7
8
  import { isLoopbackHost } from './serve-resource-auth.js';
8
9
  import { createServiceHandler } from './service.js';
@@ -48,7 +49,9 @@ export async function serveLocalService(options = {}) {
48
49
  const delegatedCredentials = directCustomerAuth
49
50
  ? createLocalDevtoolsDelegatedCredentialSource()
50
51
  : undefined;
52
+ const capabilities = options.runtime?.capabilities ?? localWebCapabilities();
51
53
  const registry = new ServerRegistry(undefined, undefined, configStore, {
54
+ capabilities,
52
55
  customerVerifierFactory,
53
56
  ...(delegatedCredentials === undefined
54
57
  ? {}
@@ -62,6 +65,17 @@ export async function serveLocalService(options = {}) {
62
65
  : { localDevtoolsDelegatedExchange: options.localDevtoolsDelegatedExchange }),
63
66
  });
64
67
  const handler = createServiceHandler(registry, {
68
+ capabilities,
69
+ deployGate: {
70
+ authorize: () => ({
71
+ ok: true,
72
+ identity: {
73
+ subject: 'local-operator',
74
+ email: 'local-operator@localhost',
75
+ superAdmin: true,
76
+ },
77
+ }),
78
+ },
65
79
  controlPlaneStore,
66
80
  configStore,
67
81
  assetStore: new InMemoryAssetStore(),
@@ -1,10 +1,20 @@
1
1
  import { resolveMcpSubdomainTenant } from '@noodle-borg/control-plane/portable';
2
2
  import { normalizePublicBaseDomain, parseCanonicalPublicMcpUrl, parseLegacyTenantMcpPath, } from '@noodle-borg/module';
3
3
  import { resolveTenantBridgeAuthVariables } from './managed-config-expressions.js';
4
+ import { createHostedMcpRequestStateManager } from './mcp-protocol-runtime.js';
4
5
  import { resolveConfigScope, } from './store.js';
5
6
  export function isLoopbackHost(host) {
6
7
  return host === '127.0.0.1' || host === '::1' || host === 'localhost';
7
8
  }
9
+ export function resolveMcpRequestState(options, secretBox) {
10
+ return (options.mcpRequestState ??
11
+ createHostedMcpRequestStateManager({
12
+ ...(options.wrappingMasterKey === undefined && options.secretMasterKey !== undefined
13
+ ? { secretMasterKey: options.secretMasterKey }
14
+ : {}),
15
+ ...(secretBox === undefined ? {} : { secretBox }),
16
+ }));
17
+ }
8
18
  export function assertLocalDevtoolsServiceBoundary(host, options) {
9
19
  if (options.localDevtoolsDirectFirebaseAuth === true && !isLoopbackHost(host)) {
10
20
  throw new Error('local Devtools Firebase verification requires a loopback service bind');
@@ -2,6 +2,7 @@ import { InMemoryDailyCounterStore } from '@noodle-borg/admission-limits/portabl
2
2
  import { InMemoryAssistantAppearanceSettingsStore, InMemoryAssistantStore, } from '@noodle-borg/assistant-gateway/portable';
3
3
  import { allowAllGate, InMemoryControlPlaneStore } from '@noodle-borg/control-plane/portable';
4
4
  import { dispatchKnowledgeRequest } from '@noodle-borg/knowledge-operations/portable';
5
+ import { capabilityOperatorRoute } from '@noodle-borg/managed-capabilities';
5
6
  import { OPENAI_APPS_CHALLENGE_PATH } from '@noodle-borg/module';
6
7
  import { applySecurityHeaders, createMcpRouter, enforceHttps, noopLogger, sendJson, } from '@noodle-borg/transport-http';
7
8
  import { AnonymousConsumerLimiter, createAdmissionGate } from './admission.js';
@@ -163,7 +164,12 @@ export function createServiceHandler(registry, options = {}) {
163
164
  });
164
165
  archiveSweeper.maybeSweep();
165
166
  const moduleRouteDeps = {
166
- routes: moduleHost.routes,
167
+ routes: [
168
+ ...moduleHost.routes,
169
+ ...(options.capabilities === undefined
170
+ ? []
171
+ : [capabilityOperatorRoute(options.capabilities)]),
172
+ ],
167
173
  logger,
168
174
  gate,
169
175
  controlPlane,
@@ -0,0 +1,39 @@
1
+ import { CapabilityError } from '@noodle-borg/managed-capabilities';
2
+ import { evaluateToolAuthorization } from '@noodle-borg/protocol';
3
+ import { WebCapabilityConnector } from '@noodle-borg/runtime';
4
+ export function deploymentWebConnector(artifact, tenant, deploymentId, service) {
5
+ if (!artifact.server.capabilities?.length)
6
+ return undefined;
7
+ return new WebCapabilityConnector(artifact.server.capabilities, async (declaration, request, call) => {
8
+ if (service === undefined ||
9
+ deploymentId === undefined ||
10
+ call.execution === undefined ||
11
+ call.capabilityBudget === undefined) {
12
+ throw new CapabilityError('capability_unavailable');
13
+ }
14
+ return service.execute(declaration, request, {
15
+ tenant,
16
+ deploymentId,
17
+ executionId: call.execution.id,
18
+ authorized: evaluateToolAuthorization(declaration.authorization === undefined
19
+ ? undefined
20
+ : {
21
+ ...(declaration.authorization.discovery === 'public'
22
+ ? { discovery: 'public' }
23
+ : {}),
24
+ ...(declaration.authorization.requiredScopes === undefined
25
+ ? {}
26
+ : { requiredScopes: declaration.authorization.requiredScopes }),
27
+ ...(declaration.authorization.allowedRoles === undefined
28
+ ? {}
29
+ : { allowedRoles: declaration.authorization.allowedRoles }),
30
+ }, call.caller).allow,
31
+ anonymous: call.caller === undefined || call.caller.identityKind === 'anonymous',
32
+ ...(call.caller === undefined ? {} : { subject: call.caller.subject }),
33
+ ...(call.publicAdmission === undefined ? {} : { network: call.publicAdmission.network }),
34
+ budget: call.capabilityBudget,
35
+ ...(call.signal === undefined ? {} : { signal: call.signal }),
36
+ });
37
+ });
38
+ }
39
+ //# sourceMappingURL=web-capabilities.js.map