@noodleseed/one 0.169.0 → 0.171.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 (189) hide show
  1. package/dist/cli.d.ts.map +1 -1
  2. package/dist/cli.js +6 -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/commands/catalog.d.ts.map +1 -1
  9. package/dist/commands/catalog.js +2 -1
  10. package/dist/commands/catalog.js.map +1 -1
  11. package/dist/commands/whatsapp-ops.d.ts +13 -0
  12. package/dist/commands/whatsapp-ops.d.ts.map +1 -0
  13. package/dist/commands/whatsapp-ops.js +244 -0
  14. package/dist/commands/whatsapp-ops.js.map +1 -0
  15. package/dist/commands/whatsapp-output.d.ts +3 -0
  16. package/dist/commands/whatsapp-output.d.ts.map +1 -0
  17. package/dist/commands/whatsapp-output.js +70 -0
  18. package/dist/commands/whatsapp-output.js.map +1 -0
  19. package/dist/dev.js +2 -0
  20. package/dist/dev.js.map +1 -1
  21. package/dist/index.d.ts +1 -1
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +1 -1
  24. package/dist/index.js.map +1 -1
  25. package/dist/plugin-mode/plugin-operation-contract.d.ts +3 -3
  26. package/node_modules/@noodle-borg/agent-kit/dist/curated/command-groups.js +8 -0
  27. package/node_modules/@noodle-borg/agent-kit/dist/curated/error-fixes.js +1 -0
  28. package/node_modules/@noodle-borg/agent-kit/dist/generated/example-files.js +2 -2
  29. package/node_modules/@noodle-borg/agent-kit/dist/generated/surface.js +5 -0
  30. package/node_modules/@noodle-borg/agent-kit/dist/skill-authoring-refs.js +3 -2
  31. package/node_modules/@noodle-borg/agent-kit/dist/skill-embedded-assistant-ref.js +6 -0
  32. package/node_modules/@noodle-borg/agent-kit/package.json +1 -1
  33. package/node_modules/@noodle-borg/app-audit/dist/audit-embedded-assistant.js +2 -0
  34. package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-configuration.js +2 -1
  35. package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-interactive.d.ts +1 -0
  36. package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-interactive.js +4 -1
  37. package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-model-context.js +9 -4
  38. package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-turn-context.d.ts +16 -0
  39. package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-turn-context.js +19 -0
  40. package/node_modules/@noodle-borg/assistant-gateway/dist/channel-coordinator.d.ts +145 -0
  41. package/node_modules/@noodle-borg/assistant-gateway/dist/channel-coordinator.js +378 -0
  42. package/node_modules/@noodle-borg/assistant-gateway/dist/channel-inbox.js +160 -0
  43. package/node_modules/@noodle-borg/assistant-gateway/dist/channel-provider-blocks.d.ts +18 -0
  44. package/node_modules/@noodle-borg/assistant-gateway/dist/channel-provider-blocks.js +69 -0
  45. package/node_modules/@noodle-borg/assistant-gateway/dist/channel-spend.js +82 -0
  46. package/node_modules/@noodle-borg/assistant-gateway/dist/channel-store.d.ts +42 -0
  47. package/node_modules/@noodle-borg/assistant-gateway/dist/channel-store.js +76 -0
  48. package/node_modules/@noodle-borg/assistant-gateway/dist/channel-types.d.ts +134 -0
  49. package/node_modules/@noodle-borg/assistant-gateway/dist/channel-types.js +72 -0
  50. package/node_modules/@noodle-borg/assistant-gateway/dist/channel-work.d.ts +20 -0
  51. package/node_modules/@noodle-borg/assistant-gateway/dist/channel-work.js +221 -0
  52. package/node_modules/@noodle-borg/assistant-gateway/dist/messaging-tool-dispatch.d.ts +15 -0
  53. package/node_modules/@noodle-borg/assistant-gateway/dist/messaging-tool-dispatch.js +34 -0
  54. package/node_modules/@noodle-borg/assistant-gateway/dist/model-request.d.ts +19 -1
  55. package/node_modules/@noodle-borg/assistant-gateway/dist/model-request.js +22 -6
  56. package/node_modules/@noodle-borg/assistant-gateway/dist/portable.d.ts +7 -0
  57. package/node_modules/@noodle-borg/assistant-gateway/dist/portable.js +7 -0
  58. package/node_modules/@noodle-borg/assistant-gateway/dist/postgres-assistant-appearance-store.js +83 -0
  59. package/node_modules/@noodle-borg/assistant-gateway/dist/postgres-assistant-elevation.js +151 -0
  60. package/node_modules/@noodle-borg/assistant-gateway/dist/postgres-assistant-interaction-writes.js +45 -0
  61. package/node_modules/@noodle-borg/assistant-gateway/dist/postgres-assistant-interactions.js +340 -0
  62. package/node_modules/@noodle-borg/assistant-gateway/dist/postgres-assistant.js +439 -0
  63. package/node_modules/@noodle-borg/assistant-gateway/dist/postgres-channel-store.js +102 -0
  64. package/node_modules/@noodle-borg/assistant-gateway/dist/postgres-continuity-store.js +159 -0
  65. package/node_modules/@noodle-borg/assistant-gateway/dist/postgres-elevation-store.js +110 -0
  66. package/node_modules/@noodle-borg/assistant-gateway/dist/postgres-embed-store.js +134 -0
  67. package/node_modules/@noodle-borg/assistant-gateway/dist/postgres.js +11 -0
  68. package/node_modules/@noodle-borg/assistant-gateway/dist/public-surface.d.ts +8 -0
  69. package/node_modules/@noodle-borg/assistant-gateway/dist/public-surface.js +23 -0
  70. package/node_modules/@noodle-borg/authoring/dist/assistant.d.ts +19 -4
  71. package/node_modules/@noodle-borg/authoring/dist/assistant.js +51 -20
  72. package/node_modules/@noodle-borg/authoring/dist/index.d.ts +2 -1
  73. package/node_modules/@noodle-borg/authoring/dist/index.js +2 -1
  74. package/node_modules/@noodle-borg/authoring/dist/load-authored.js +1 -1
  75. package/node_modules/@noodle-borg/authoring/dist/recording.d.ts +2 -1
  76. package/node_modules/@noodle-borg/authoring/dist/recording.js +29 -1
  77. package/node_modules/@noodle-borg/authoring/dist/server.d.ts +3 -0
  78. package/node_modules/@noodle-borg/authoring/dist/server.js +5 -1
  79. package/node_modules/@noodle-borg/authoring/dist/web-capabilities.d.ts +17 -0
  80. package/node_modules/@noodle-borg/authoring/dist/web-capabilities.js +15 -0
  81. package/node_modules/@noodle-borg/authoring/package.json +1 -0
  82. package/node_modules/@noodle-borg/capabilities/dist/index.js +7 -0
  83. package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-channels.js +121 -0
  84. package/node_modules/@noodle-borg/cli-catalog/dist/catalog-data-hosted-observability.js +102 -0
  85. package/node_modules/@noodle-borg/cli-catalog/dist/index.js +1 -0
  86. package/node_modules/@noodle-borg/compiler/dist/artifact/assemble.js +3 -0
  87. package/node_modules/@noodle-borg/compiler/dist/artifact/config.js +1 -1
  88. package/node_modules/@noodle-borg/compiler/dist/artifact/types.d.ts +2 -0
  89. package/node_modules/@noodle-borg/compiler/dist/artifact/version.d.ts +2 -1
  90. package/node_modules/@noodle-borg/compiler/dist/artifact/version.js +2 -1
  91. package/node_modules/@noodle-borg/compiler/dist/compile.js +2 -0
  92. package/node_modules/@noodle-borg/compiler/dist/errors.d.ts +1 -1
  93. package/node_modules/@noodle-borg/compiler/dist/fulfilment-emit.js +18 -3
  94. package/node_modules/@noodle-borg/compiler/dist/manifest/schema.d.ts +106 -12
  95. package/node_modules/@noodle-borg/compiler/dist/manifest/schema.js +60 -29
  96. package/node_modules/@noodle-borg/compiler/dist/manifest/website-projection.d.ts +1 -0
  97. package/node_modules/@noodle-borg/compiler/dist/manifest/website-projection.js +19 -0
  98. package/node_modules/@noodle-borg/compiler/dist/web-capabilities.js +55 -0
  99. package/node_modules/@noodle-borg/compiler/package.json +1 -0
  100. package/node_modules/@noodle-borg/connector-http/dist/ssrf.js +5 -0
  101. package/node_modules/@noodle-borg/knowledge-crawl/dist/bounded-body.js +38 -0
  102. package/node_modules/@noodle-borg/knowledge-crawl/dist/first-party.js +2 -3
  103. package/node_modules/@noodle-borg/knowledge-crawl/dist/html-text.js +10 -2
  104. package/node_modules/@noodle-borg/knowledge-crawl/dist/index.d.ts +1 -0
  105. package/node_modules/@noodle-borg/knowledge-crawl/dist/index.js +1 -0
  106. package/node_modules/@noodle-borg/knowledge-crawl/dist/page-reader.d.ts +26 -0
  107. package/node_modules/@noodle-borg/knowledge-crawl/dist/page-reader.js +127 -0
  108. package/node_modules/@noodle-borg/knowledge-crawl/dist/robots.js +48 -23
  109. package/node_modules/@noodle-borg/knowledge-crawl/package.json +1 -0
  110. package/node_modules/@noodle-borg/managed-capabilities/dist/budget.d.ts +29 -0
  111. package/node_modules/@noodle-borg/managed-capabilities/dist/budget.js +124 -0
  112. package/node_modules/@noodle-borg/managed-capabilities/dist/contracts.d.ts +212 -0
  113. package/node_modules/@noodle-borg/managed-capabilities/dist/contracts.js +113 -0
  114. package/node_modules/@noodle-borg/managed-capabilities/dist/errors.d.ts +8 -0
  115. package/node_modules/@noodle-borg/managed-capabilities/dist/errors.js +21 -0
  116. package/node_modules/@noodle-borg/managed-capabilities/dist/executor.d.ts +26 -0
  117. package/node_modules/@noodle-borg/managed-capabilities/dist/executor.js +156 -0
  118. package/node_modules/@noodle-borg/managed-capabilities/dist/limits.d.ts +15 -0
  119. package/node_modules/@noodle-borg/managed-capabilities/dist/limits.js +15 -0
  120. package/node_modules/@noodle-borg/managed-capabilities/dist/operator-contracts.d.ts +159 -0
  121. package/node_modules/@noodle-borg/managed-capabilities/dist/operator-contracts.js +69 -0
  122. package/node_modules/@noodle-borg/managed-capabilities/dist/operator-route.d.ts +5 -0
  123. package/node_modules/@noodle-borg/managed-capabilities/dist/operator-route.js +160 -0
  124. package/node_modules/@noodle-borg/managed-capabilities/dist/policy-store.d.ts +34 -0
  125. package/node_modules/@noodle-borg/managed-capabilities/dist/policy-store.js +61 -0
  126. package/node_modules/@noodle-borg/managed-capabilities/dist/portable.d.ts +10 -0
  127. package/node_modules/@noodle-borg/managed-capabilities/dist/portable.js +10 -0
  128. package/node_modules/@noodle-borg/managed-capabilities/dist/service.d.ts +83 -0
  129. package/node_modules/@noodle-borg/managed-capabilities/dist/service.js +139 -0
  130. package/node_modules/@noodle-borg/managed-capabilities/dist/urls.d.ts +3 -0
  131. package/node_modules/@noodle-borg/managed-capabilities/dist/urls.js +30 -0
  132. package/node_modules/@noodle-borg/managed-capabilities/package.json +49 -0
  133. package/node_modules/@noodle-borg/module/dist/contract.d.ts +11 -0
  134. package/node_modules/@noodle-borg/module-audit/dist/index.js +37 -0
  135. package/node_modules/@noodle-borg/module-audit/dist/postgres-audit.js +126 -0
  136. package/node_modules/@noodle-borg/module-audit/dist/route.js +66 -0
  137. package/node_modules/@noodle-borg/runtime/dist/confirmation.js +29 -0
  138. package/node_modules/@noodle-borg/runtime/dist/connector/types.d.ts +2 -0
  139. package/node_modules/@noodle-borg/runtime/dist/execute.d.ts +3 -0
  140. package/node_modules/@noodle-borg/runtime/dist/execute.js +6 -1
  141. package/node_modules/@noodle-borg/runtime/dist/index.d.ts +2 -1
  142. package/node_modules/@noodle-borg/runtime/dist/index.js +2 -1
  143. package/node_modules/@noodle-borg/runtime/dist/interactive.js +10 -1
  144. package/node_modules/@noodle-borg/runtime/dist/managed-origins.js +8 -4
  145. package/node_modules/@noodle-borg/runtime/dist/operation-execution.js +3 -0
  146. package/node_modules/@noodle-borg/runtime/dist/postgres-state-handles.js +311 -0
  147. package/node_modules/@noodle-borg/runtime/dist/postgres.js +4 -0
  148. package/node_modules/@noodle-borg/runtime/dist/result-meta.d.ts +2 -0
  149. package/node_modules/@noodle-borg/runtime/dist/result-meta.js +6 -0
  150. package/node_modules/@noodle-borg/runtime/dist/result.d.ts +4 -0
  151. package/node_modules/@noodle-borg/runtime/dist/web-capabilities.d.ts +71 -0
  152. package/node_modules/@noodle-borg/runtime/dist/web-capabilities.js +41 -0
  153. package/node_modules/@noodle-borg/runtime/package.json +1 -0
  154. package/node_modules/@noodle-borg/service/dist/assistant-composition.js +18 -0
  155. package/node_modules/@noodle-borg/service/dist/build-info.js +5 -2
  156. package/node_modules/@noodle-borg/service/dist/business-information/source-ingestion-coordinator.js +7 -0
  157. package/node_modules/@noodle-borg/service/dist/channels/360dialog.js +233 -0
  158. package/node_modules/@noodle-borg/service/dist/channels/cipher.js +37 -0
  159. package/node_modules/@noodle-borg/service/dist/channels/composition.js +37 -0
  160. package/node_modules/@noodle-borg/service/dist/channels/inference-guard.js +53 -0
  161. package/node_modules/@noodle-borg/service/dist/channels/runtime.js +337 -0
  162. package/node_modules/@noodle-borg/service/dist/channels/worker-loop.js +50 -0
  163. package/node_modules/@noodle-borg/service/dist/local-options.d.ts +1 -0
  164. package/node_modules/@noodle-borg/service/dist/local-web-capabilities.js +13 -0
  165. package/node_modules/@noodle-borg/service/dist/mcp-protocol-runtime.js +21 -0
  166. package/node_modules/@noodle-borg/service/dist/modules/route-dispatch.js +13 -0
  167. package/node_modules/@noodle-borg/service/dist/registry-compile.js +3 -0
  168. package/node_modules/@noodle-borg/service/dist/registry-types.d.ts +1 -0
  169. package/node_modules/@noodle-borg/service/dist/registry.js +3 -0
  170. package/node_modules/@noodle-borg/service/dist/routes/assistant-agent.js +66 -35
  171. package/node_modules/@noodle-borg/service/dist/routes/assistant-interactions.js +7 -4
  172. package/node_modules/@noodle-borg/service/dist/routes/assistant-model-binding.js +6 -2
  173. package/node_modules/@noodle-borg/service/dist/routes/business-information-channels.js +14 -1
  174. package/node_modules/@noodle-borg/service/dist/routes/whatsapp.js +238 -0
  175. package/node_modules/@noodle-borg/service/dist/serve-local.js +14 -0
  176. package/node_modules/@noodle-borg/service/dist/serve-resource-auth.js +10 -0
  177. package/node_modules/@noodle-borg/service/dist/service.js +37 -33
  178. package/node_modules/@noodle-borg/service/dist/web-capabilities.js +39 -0
  179. package/node_modules/@noodle-borg/service/package.json +3 -1
  180. package/node_modules/@noodle-borg/wire-contracts/dist/application-channels.d.ts +33 -0
  181. package/node_modules/@noodle-borg/wire-contracts/dist/application-channels.js +9 -0
  182. package/node_modules/@noodle-borg/wire-contracts/dist/index.d.ts +2 -0
  183. package/node_modules/@noodle-borg/wire-contracts/dist/index.js +2 -0
  184. package/node_modules/@noodle-borg/wire-contracts/dist/service-info.d.ts +2 -0
  185. package/node_modules/@noodle-borg/wire-contracts/dist/service-info.js +10 -2
  186. package/node_modules/@noodle-borg/wire-contracts/dist/whatsapp.d.ts +426 -0
  187. package/node_modules/@noodle-borg/wire-contracts/dist/whatsapp.js +213 -0
  188. package/node_modules/@noodle-borg/wire-contracts/package.json +1 -0
  189. package/package.json +3 -2
@@ -0,0 +1,311 @@
1
+ import { assertExpectedStateRevision, assertNoSecretValue, assertSchemaValue, assertStateHandleNotCompleted, createMutableStateHandleRecord, stateHandleRecordForMutation, toPublicStateHandleRecord, } from './state-handles.js';
2
+ /** Covers a request admitted just before the anonymous session's absolute expiry. */
3
+ const STATE_OWNER_REDIRECT_GRACE_MS = 5 * 60 * 1000;
4
+ export class PostgresStateHandleStore {
5
+ #pool;
6
+ #deploymentId;
7
+ #state;
8
+ #now;
9
+ constructor(pool, options) {
10
+ this.#pool = pool;
11
+ this.#deploymentId = options.deploymentId;
12
+ this.#state = options.state;
13
+ this.#now = options.now ?? (() => new Date());
14
+ }
15
+ async read(input) {
16
+ const def = this.#definition(input.handle);
17
+ const owner = ownerKey(def, input);
18
+ const key = input.key ?? 'default';
19
+ const read = async (client) => {
20
+ const nowDate = this.#now();
21
+ const resolvedOwner = def.claimOnAuthentication === true
22
+ ? await resolveOperationOwner(client, this.#deploymentId, input.handle, owner, nowDate)
23
+ : owner;
24
+ const row = await selectRow(client, this.#deploymentId, input.handle, resolvedOwner, key);
25
+ const now = nowDate.getTime();
26
+ if (row === undefined) {
27
+ return toPublicStateHandleRecord(createMutableStateHandleRecord(input.handle, key, def.ttlSeconds, now), now);
28
+ }
29
+ assertVersion(row, def);
30
+ return toPublicStateHandleRecord(mutableFromRow(row), now);
31
+ };
32
+ return def.claimOnAuthentication === true
33
+ ? this.#withTransaction((client) => read(client))
34
+ : read(this.#pool);
35
+ }
36
+ async patch(input) {
37
+ return this.#withTransaction(async (client) => {
38
+ const def = this.#definition(input.handle);
39
+ const owner = ownerKey(def, input);
40
+ const key = input.key ?? 'default';
41
+ const nowDate = this.#now();
42
+ const resolvedOwner = def.claimOnAuthentication === true
43
+ ? await resolveOperationOwner(client, this.#deploymentId, input.handle, owner, nowDate)
44
+ : owner;
45
+ const row = await selectRow(client, this.#deploymentId, input.handle, resolvedOwner, key, true);
46
+ if (row !== undefined)
47
+ assertVersion(row, def);
48
+ const now = nowDate.getTime();
49
+ const current = stateHandleRecordForMutation(row ? mutableFromRow(row) : undefined, input.handle, key, def.ttlSeconds, now);
50
+ assertStateHandleNotCompleted(current);
51
+ assertExpectedStateRevision(current, input.expectedRevision);
52
+ assertNoSecretValue(input.value);
53
+ const value = { ...current.value, ...input.value };
54
+ assertSchemaValue(def.schema, value);
55
+ const next = {
56
+ ...current,
57
+ value,
58
+ revision: current.revision + 1,
59
+ updatedAt: now,
60
+ };
61
+ await upsertRow(client, this.#deploymentId, resolvedOwner, def.version, next);
62
+ return toPublicStateHandleRecord(next, now);
63
+ });
64
+ }
65
+ async complete(input) {
66
+ return this.#withTransaction(async (client) => {
67
+ const def = this.#definition(input.handle);
68
+ const owner = ownerKey(def, input);
69
+ const key = input.key ?? 'default';
70
+ const nowDate = this.#now();
71
+ const resolvedOwner = def.claimOnAuthentication === true
72
+ ? await resolveOperationOwner(client, this.#deploymentId, input.handle, owner, nowDate)
73
+ : owner;
74
+ const row = await selectRow(client, this.#deploymentId, input.handle, resolvedOwner, key, true);
75
+ if (row !== undefined)
76
+ assertVersion(row, def);
77
+ const now = nowDate.getTime();
78
+ const current = stateHandleRecordForMutation(row ? mutableFromRow(row) : undefined, input.handle, key, def.ttlSeconds, now);
79
+ assertStateHandleNotCompleted(current);
80
+ assertExpectedStateRevision(current, input.expectedRevision);
81
+ const next = {
82
+ ...current,
83
+ status: 'completed',
84
+ revision: current.revision + 1,
85
+ updatedAt: now,
86
+ };
87
+ await upsertRow(client, this.#deploymentId, resolvedOwner, def.version, next);
88
+ return toPublicStateHandleRecord(next, now);
89
+ });
90
+ }
91
+ async pruneExpired() {
92
+ const result = await this.#pool.query(`DELETE FROM state_handle_records
93
+ WHERE deployment_id = $1 AND expires_at IS NOT NULL AND expires_at <= $2`, [this.#deploymentId, this.#now()]);
94
+ await this.#pool.query(`DELETE FROM state_handle_owner_redirects
95
+ WHERE deployment_id = $1 AND expires_at <= $2`, [this.#deploymentId, new Date(this.#now().getTime() - STATE_OWNER_REDIRECT_GRACE_MS)]);
96
+ return result.rowCount ?? 0;
97
+ }
98
+ #definition(handle) {
99
+ const def = this.#state.handles[handle];
100
+ if (def === undefined)
101
+ throw new Error(`unknown state handle "${handle}"`);
102
+ return def;
103
+ }
104
+ async #withTransaction(work) {
105
+ const client = await this.#pool.connect();
106
+ try {
107
+ await client.query('BEGIN');
108
+ const result = await work(client);
109
+ await client.query('COMMIT');
110
+ return result;
111
+ }
112
+ catch (err) {
113
+ await client.query('ROLLBACK');
114
+ throw err;
115
+ }
116
+ finally {
117
+ client.release();
118
+ }
119
+ }
120
+ }
121
+ export async function ensureStateHandleSchema(pool) {
122
+ await pool.query(`
123
+ CREATE TABLE IF NOT EXISTS state_handle_records (
124
+ deployment_id text NOT NULL,
125
+ handle_name text NOT NULL,
126
+ owner_key text NOT NULL,
127
+ state_key text NOT NULL,
128
+ handle_version text NOT NULL,
129
+ value jsonb NOT NULL,
130
+ revision bigint NOT NULL,
131
+ status text NOT NULL CHECK (status IN ('active', 'completed')),
132
+ created_at timestamptz NOT NULL,
133
+ updated_at timestamptz NOT NULL,
134
+ expires_at timestamptz,
135
+ PRIMARY KEY (deployment_id, handle_name, owner_key, state_key)
136
+ )
137
+ `);
138
+ await pool.query(`
139
+ CREATE INDEX IF NOT EXISTS state_handle_records_expiry_idx
140
+ ON state_handle_records (expires_at)
141
+ WHERE expires_at IS NOT NULL
142
+ `);
143
+ await pool.query(`
144
+ CREATE TABLE IF NOT EXISTS state_handle_owner_redirects (
145
+ deployment_id text NOT NULL,
146
+ handle_name text NOT NULL,
147
+ source_owner_key text NOT NULL,
148
+ target_owner_key text NOT NULL,
149
+ created_at timestamptz NOT NULL,
150
+ expires_at timestamptz NOT NULL,
151
+ PRIMARY KEY (deployment_id, handle_name, source_owner_key),
152
+ CHECK (source_owner_key <> target_owner_key)
153
+ )
154
+ `);
155
+ await pool.query(`
156
+ CREATE INDEX IF NOT EXISTS state_handle_owner_redirects_expiry_idx
157
+ ON state_handle_owner_redirects (expires_at)
158
+ `);
159
+ }
160
+ /**
161
+ * Rebind opted-in caller state inside the elevation transaction supplied by assistant-gateway.
162
+ * Values are never decoded or rewritten: changing only `owner_key` preserves every lifecycle field.
163
+ */
164
+ export async function adoptCallerState(client, input) {
165
+ if (input.sourceCallerSubject === input.targetCallerSubject) {
166
+ return { ok: true, adoptedHandles: [], adoptedRecords: 0 };
167
+ }
168
+ const handles = [...new Set(input.handles)].sort();
169
+ for (const handle of handles) {
170
+ // Anonymous -> authenticated is directional. Every opted state operation takes the source
171
+ // lock before following its redirect and then takes the target lock, so the adoption uses the
172
+ // same order while still serializing concurrent creates under either owner.
173
+ await lockOwner(client, input.deploymentId, handle, input.sourceCallerSubject);
174
+ await lockOwner(client, input.deploymentId, handle, input.targetCallerSubject);
175
+ }
176
+ if (handles.length === 0) {
177
+ return { ok: true, adoptedHandles: [], adoptedRecords: 0 };
178
+ }
179
+ const redirect = await client.query(`SELECT handle_name, target_owner_key
180
+ FROM state_handle_owner_redirects
181
+ WHERE deployment_id = $1
182
+ AND handle_name = ANY($2::text[])
183
+ AND source_owner_key = $3
184
+ AND expires_at > $4`, [
185
+ input.deploymentId,
186
+ handles,
187
+ input.sourceCallerSubject,
188
+ new Date(input.now.getTime() - STATE_OWNER_REDIRECT_GRACE_MS),
189
+ ]);
190
+ if (redirect.rows.some((row) => row.target_owner_key !== input.targetCallerSubject)) {
191
+ return { ok: false, reason: 'state_key_conflict' };
192
+ }
193
+ const collision = await client.query(`SELECT 1
194
+ FROM state_handle_records AS source
195
+ JOIN state_handle_records AS target
196
+ ON target.deployment_id = source.deployment_id
197
+ AND target.handle_name = source.handle_name
198
+ AND target.state_key = source.state_key
199
+ WHERE source.deployment_id = $1
200
+ AND source.handle_name = ANY($2::text[])
201
+ AND source.owner_key = $3
202
+ AND target.owner_key = $4
203
+ LIMIT 1`, [input.deploymentId, handles, input.sourceCallerSubject, input.targetCallerSubject]);
204
+ if ((collision.rowCount ?? 0) > 0) {
205
+ return { ok: false, reason: 'state_key_conflict' };
206
+ }
207
+ const moved = await client.query(`UPDATE state_handle_records
208
+ SET owner_key = $4
209
+ WHERE deployment_id = $1
210
+ AND handle_name = ANY($2::text[])
211
+ AND owner_key = $3`, [input.deploymentId, handles, input.sourceCallerSubject, input.targetCallerSubject]);
212
+ await client.query(`INSERT INTO state_handle_owner_redirects
213
+ (deployment_id, handle_name, source_owner_key, target_owner_key, created_at, expires_at)
214
+ SELECT $1, handle_name, $3, $4, $5, $6
215
+ FROM unnest($2::text[]) AS handle_name
216
+ ON CONFLICT (deployment_id, handle_name, source_owner_key) DO UPDATE SET
217
+ target_owner_key = EXCLUDED.target_owner_key,
218
+ created_at = EXCLUDED.created_at,
219
+ expires_at = EXCLUDED.expires_at`, [
220
+ input.deploymentId,
221
+ handles,
222
+ input.sourceCallerSubject,
223
+ input.targetCallerSubject,
224
+ input.now,
225
+ input.redirectExpiresAt,
226
+ ]);
227
+ return {
228
+ ok: true,
229
+ adoptedHandles: handles,
230
+ adoptedRecords: moved.rowCount ?? 0,
231
+ };
232
+ }
233
+ async function selectRow(client, deploymentId, handle, owner, key, forUpdate = false) {
234
+ const result = await client.query(`SELECT handle_name, state_key, handle_version, value, revision, status,
235
+ created_at, updated_at, expires_at
236
+ FROM state_handle_records
237
+ WHERE deployment_id = $1 AND handle_name = $2 AND owner_key = $3 AND state_key = $4
238
+ ${forUpdate ? 'FOR UPDATE' : ''}`, [deploymentId, handle, owner, key]);
239
+ return result.rows[0];
240
+ }
241
+ async function upsertRow(client, deploymentId, owner, version, record) {
242
+ await client.query(`INSERT INTO state_handle_records
243
+ (deployment_id, handle_name, owner_key, state_key, handle_version, value, revision,
244
+ status, created_at, updated_at, expires_at)
245
+ VALUES ($1, $2, $3, $4, $5, $6::jsonb, $7, $8, $9, $10, $11)
246
+ ON CONFLICT (deployment_id, handle_name, owner_key, state_key) DO UPDATE SET
247
+ handle_version = EXCLUDED.handle_version,
248
+ value = EXCLUDED.value,
249
+ revision = EXCLUDED.revision,
250
+ status = EXCLUDED.status,
251
+ created_at = EXCLUDED.created_at,
252
+ updated_at = EXCLUDED.updated_at,
253
+ expires_at = EXCLUDED.expires_at`, [
254
+ deploymentId,
255
+ record.handle,
256
+ owner,
257
+ record.key,
258
+ version,
259
+ JSON.stringify(record.value),
260
+ record.revision,
261
+ record.status,
262
+ new Date(record.createdAt),
263
+ new Date(record.updatedAt),
264
+ record.expiresAt === undefined ? null : new Date(record.expiresAt),
265
+ ]);
266
+ }
267
+ function ownerKey(def, input) {
268
+ return def.scope === 'caller' ? (input.callerSubject ?? 'anonymous') : 'deployment';
269
+ }
270
+ async function lockOwner(client, deploymentId, handle, owner) {
271
+ await client.query('SELECT pg_advisory_xact_lock(hashtextextended($1, 0))', [
272
+ stateOwnerLockKey(deploymentId, handle, owner),
273
+ ]);
274
+ }
275
+ /** PostgreSQL text rejects NUL, so length-prefix each untrusted segment instead of using a sentinel. */
276
+ function stateOwnerLockKey(deploymentId, handle, owner) {
277
+ return `state-owner:${deploymentId.length}:${deploymentId}:${handle.length}:${handle}:${owner.length}:${owner}`;
278
+ }
279
+ async function resolveOperationOwner(client, deploymentId, handle, owner, now) {
280
+ await lockOwner(client, deploymentId, handle, owner);
281
+ const redirect = await client.query(`SELECT target_owner_key
282
+ FROM state_handle_owner_redirects
283
+ WHERE deployment_id = $1 AND handle_name = $2 AND source_owner_key = $3 AND expires_at > $4`, [deploymentId, handle, owner, new Date(now.getTime() - STATE_OWNER_REDIRECT_GRACE_MS)]);
284
+ const target = redirect.rows[0]?.target_owner_key;
285
+ if (target === undefined)
286
+ return owner;
287
+ await lockOwner(client, deploymentId, handle, target);
288
+ return target;
289
+ }
290
+ function assertVersion(row, def) {
291
+ if (row.handle_version !== def.version) {
292
+ throw new Error(`state handle version mismatch for "${row.handle_name}": stored ${row.handle_version}, current ${def.version}`);
293
+ }
294
+ }
295
+ function mutableFromRow(row) {
296
+ const value = typeof row.value === 'object' && row.value !== null && !Array.isArray(row.value)
297
+ ? row.value
298
+ : {};
299
+ const expiresAt = row.expires_at === null ? undefined : new Date(row.expires_at).getTime();
300
+ return {
301
+ handle: row.handle_name,
302
+ key: row.state_key,
303
+ value,
304
+ revision: Number(row.revision),
305
+ status: row.status,
306
+ createdAt: new Date(row.created_at).getTime(),
307
+ updatedAt: new Date(row.updated_at).getTime(),
308
+ ...(expiresAt !== undefined ? { expiresAt } : {}),
309
+ };
310
+ }
311
+ //# sourceMappingURL=postgres-state-handles.js.map
@@ -0,0 +1,4 @@
1
+ /** PostgreSQL state-handle persistence for hosted composition. */
2
+ export * from './postgres-state-handles.js';
3
+ export * from './state-handle-ownership.js';
4
+ //# sourceMappingURL=postgres.js.map
@@ -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
  },
@@ -0,0 +1,18 @@
1
+ /** Browser and messaging resolve model, execution and tenant policy from one composition. */
2
+ export function assistantRouteDependencies(options, core) {
3
+ return {
4
+ ...core,
5
+ ...(options.publicEmbeds ? { publicEmbeds: options.publicEmbeds } : {}),
6
+ ...(options.elevations ? { elevations: options.elevations } : {}),
7
+ ...(options.elevationCoordinator ? { elevationCoordinator: options.elevationCoordinator } : {}),
8
+ ...(options.admissionCounters ? { admissionCounters: options.admissionCounters } : {}),
9
+ ...(options.admissionEnvelope ? { admissionEnvelope: options.admissionEnvelope } : {}),
10
+ ...(options.assistantModelFetch ? { modelFetch: options.assistantModelFetch } : {}),
11
+ ...(options.managedAssistantModelResolver
12
+ ? { managedModelResolver: options.managedAssistantModelResolver }
13
+ : {}),
14
+ ...(options.captureRequestEvent ? { captureRequestEvent: options.captureRequestEvent } : {}),
15
+ ...(options.clock ? { clock: options.clock } : {}),
16
+ };
17
+ }
18
+ //# sourceMappingURL=assistant-composition.js.map
@@ -1,10 +1,13 @@
1
1
  import { MIXED_CUSTOMER_AUTH_FEATURE_VERSION, serviceInfoResponseSchema, } from '@noodle-borg/wire-contracts';
2
- export function serviceInfoPayload(buildInfo, developerMcp) {
2
+ export function serviceInfoPayload(buildInfo, developerMcp, whatsapp = false) {
3
3
  return serviceInfoResponseSchema.parse({
4
4
  ok: true,
5
5
  status: 'ok',
6
6
  ...buildInfo,
7
- features: { mixedCustomerAuth: MIXED_CUSTOMER_AUTH_FEATURE_VERSION },
7
+ features: {
8
+ mixedCustomerAuth: MIXED_CUSTOMER_AUTH_FEATURE_VERSION,
9
+ ...(whatsapp ? { whatsapp: 1 } : {}),
10
+ },
8
11
  ...(developerMcp
9
12
  ? { developerPlugin: { mcpCapabilityVersion: DEVELOPER_MCP_CAPABILITY_VERSION } }
10
13
  : {}),
@@ -133,4 +133,11 @@ function boundedToken(label, value, maximum) {
133
133
  }
134
134
  return normalized;
135
135
  }
136
+ export async function drainSourceIngestion(coordinator) {
137
+ for (let attempt = 0; attempt < 100; attempt += 1) {
138
+ const result = await coordinator.runOne();
139
+ if (result.disposition !== 'completed')
140
+ return;
141
+ }
142
+ }
136
143
  //# sourceMappingURL=source-ingestion-coordinator.js.map