@harrylabsj/kiwi 0.6.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.
- package/LICENSE +201 -0
- package/README.md +150 -0
- package/contracts/candidate-agent-dto-1.0.README.md +39 -0
- package/contracts/candidate-agent-dto-1.0.schema.json +172 -0
- package/contracts/interop/kiwi-buyer-message-send.json +43 -0
- package/contracts/interop/knp-data-part-examples.json +243 -0
- package/contracts/kiwi-catalog/1.0/agent-record.schema.json +78 -0
- package/contracts/kiwi-catalog/1.0/listing-record.schema.json +88 -0
- package/contracts/kiwi-catalog/1.0/listing-search-result.schema.json +60 -0
- package/contracts/negotiation/1.0/schema.json +501 -0
- package/contracts/shopping.negotiation/0.1/capabilities.schema.json +47 -0
- package/contracts/shopping.negotiation/0.1/decision.schema.json +120 -0
- package/contracts/shopping.negotiation/0.1/policy-result.schema.json +52 -0
- package/contracts/shopping.negotiation/0.1/snapshot.schema.json +172 -0
- package/dist/a2a/client/client.d.ts +33 -0
- package/dist/a2a/client/client.js +161 -0
- package/dist/a2a/client/client.js.map +1 -0
- package/dist/a2a/client/error.d.ts +35 -0
- package/dist/a2a/client/error.js +34 -0
- package/dist/a2a/client/error.js.map +1 -0
- package/dist/a2a/client/index.d.ts +29 -0
- package/dist/a2a/client/index.js +26 -0
- package/dist/a2a/client/index.js.map +1 -0
- package/dist/a2a/client/jsonrpc.d.ts +49 -0
- package/dist/a2a/client/jsonrpc.js +85 -0
- package/dist/a2a/client/jsonrpc.js.map +1 -0
- package/dist/a2a/client/parse.d.ts +18 -0
- package/dist/a2a/client/parse.js +134 -0
- package/dist/a2a/client/parse.js.map +1 -0
- package/dist/a2a/client/types.d.ts +102 -0
- package/dist/a2a/client/types.js +26 -0
- package/dist/a2a/client/types.js.map +1 -0
- package/dist/a2a/client/url-policy.d.ts +44 -0
- package/dist/a2a/client/url-policy.js +242 -0
- package/dist/a2a/client/url-policy.js.map +1 -0
- package/dist/a2a/negotiate.d.ts +68 -0
- package/dist/a2a/negotiate.js +288 -0
- package/dist/a2a/negotiate.js.map +1 -0
- package/dist/a2a/node.d.ts +37 -0
- package/dist/a2a/node.js +155 -0
- package/dist/a2a/node.js.map +1 -0
- package/dist/a2a/server/auth.d.ts +38 -0
- package/dist/a2a/server/auth.js +112 -0
- package/dist/a2a/server/auth.js.map +1 -0
- package/dist/a2a/server/card.d.ts +19 -0
- package/dist/a2a/server/card.js +81 -0
- package/dist/a2a/server/card.js.map +1 -0
- package/dist/a2a/server/errors.d.ts +109 -0
- package/dist/a2a/server/errors.js +178 -0
- package/dist/a2a/server/errors.js.map +1 -0
- package/dist/a2a/server/handler.d.ts +22 -0
- package/dist/a2a/server/handler.js +57 -0
- package/dist/a2a/server/handler.js.map +1 -0
- package/dist/a2a/server/inbound-message.d.ts +37 -0
- package/dist/a2a/server/inbound-message.js +104 -0
- package/dist/a2a/server/inbound-message.js.map +1 -0
- package/dist/a2a/server/index.d.ts +43 -0
- package/dist/a2a/server/index.js +42 -0
- package/dist/a2a/server/index.js.map +1 -0
- package/dist/a2a/server/merchant-handler.d.ts +69 -0
- package/dist/a2a/server/merchant-handler.js +316 -0
- package/dist/a2a/server/merchant-handler.js.map +1 -0
- package/dist/a2a/server/pipeline.d.ts +69 -0
- package/dist/a2a/server/pipeline.js +329 -0
- package/dist/a2a/server/pipeline.js.map +1 -0
- package/dist/a2a/server/server.d.ts +64 -0
- package/dist/a2a/server/server.js +420 -0
- package/dist/a2a/server/server.js.map +1 -0
- package/dist/a2a/server/task-registry.d.ts +31 -0
- package/dist/a2a/server/task-registry.js +67 -0
- package/dist/a2a/server/task-registry.js.map +1 -0
- package/dist/a2a/server/throttle.d.ts +154 -0
- package/dist/a2a/server/throttle.js +289 -0
- package/dist/a2a/server/throttle.js.map +1 -0
- package/dist/a2a/server/types.d.ts +191 -0
- package/dist/a2a/server/types.js +17 -0
- package/dist/a2a/server/types.js.map +1 -0
- package/dist/a2a/server/ucp.d.ts +49 -0
- package/dist/a2a/server/ucp.js +85 -0
- package/dist/a2a/server/ucp.js.map +1 -0
- package/dist/a2a/task/index.d.ts +24 -0
- package/dist/a2a/task/index.js +22 -0
- package/dist/a2a/task/index.js.map +1 -0
- package/dist/a2a/task/ledger.d.ts +48 -0
- package/dist/a2a/task/ledger.js +65 -0
- package/dist/a2a/task/ledger.js.map +1 -0
- package/dist/a2a/task/poller.d.ts +93 -0
- package/dist/a2a/task/poller.js +184 -0
- package/dist/a2a/task/poller.js.map +1 -0
- package/dist/a2a/task/state.d.ts +72 -0
- package/dist/a2a/task/state.js +119 -0
- package/dist/a2a/task/state.js.map +1 -0
- package/dist/a2a/ucp-agent.d.ts +49 -0
- package/dist/a2a/ucp-agent.js +78 -0
- package/dist/a2a/ucp-agent.js.map +1 -0
- package/dist/agent/agent-db.d.ts +31 -0
- package/dist/agent/agent-db.js +91 -0
- package/dist/agent/agent-db.js.map +1 -0
- package/dist/agent/buyer/buyer-tools.d.ts +70 -0
- package/dist/agent/buyer/buyer-tools.js +1353 -0
- package/dist/agent/buyer/buyer-tools.js.map +1 -0
- package/dist/agent/buyer/ranker.d.ts +53 -0
- package/dist/agent/buyer/ranker.js +153 -0
- package/dist/agent/buyer/ranker.js.map +1 -0
- package/dist/agent/buyer/scheduler.d.ts +58 -0
- package/dist/agent/buyer/scheduler.js +317 -0
- package/dist/agent/buyer/scheduler.js.map +1 -0
- package/dist/agent/buyer/search-loop.d.ts +42 -0
- package/dist/agent/buyer/search-loop.js +280 -0
- package/dist/agent/buyer/search-loop.js.map +1 -0
- package/dist/agent/buyer/task-store.d.ts +178 -0
- package/dist/agent/buyer/task-store.js +637 -0
- package/dist/agent/buyer/task-store.js.map +1 -0
- package/dist/agent/buyer/types.d.ts +222 -0
- package/dist/agent/buyer/types.js +124 -0
- package/dist/agent/buyer/types.js.map +1 -0
- package/dist/agent/chat-tools.d.ts +41 -0
- package/dist/agent/chat-tools.js +193 -0
- package/dist/agent/chat-tools.js.map +1 -0
- package/dist/agent/chat-tui.d.ts +49 -0
- package/dist/agent/chat-tui.js +314 -0
- package/dist/agent/chat-tui.js.map +1 -0
- package/dist/agent/connector/fake-connector.d.ts +50 -0
- package/dist/agent/connector/fake-connector.js +138 -0
- package/dist/agent/connector/fake-connector.js.map +1 -0
- package/dist/agent/connector/http-connector.d.ts +49 -0
- package/dist/agent/connector/http-connector.js +208 -0
- package/dist/agent/connector/http-connector.js.map +1 -0
- package/dist/agent/connector/types.d.ts +103 -0
- package/dist/agent/connector/types.js +97 -0
- package/dist/agent/connector/types.js.map +1 -0
- package/dist/agent/fake-chat-model.d.ts +22 -0
- package/dist/agent/fake-chat-model.js +134 -0
- package/dist/agent/fake-chat-model.js.map +1 -0
- package/dist/agent/kernel.d.ts +258 -0
- package/dist/agent/kernel.js +1099 -0
- package/dist/agent/kernel.js.map +1 -0
- package/dist/agent/memory/schema.d.ts +32 -0
- package/dist/agent/memory/schema.js +291 -0
- package/dist/agent/memory/schema.js.map +1 -0
- package/dist/agent/memory/store.d.ts +193 -0
- package/dist/agent/memory/store.js +881 -0
- package/dist/agent/memory/store.js.map +1 -0
- package/dist/agent/memory/types.d.ts +139 -0
- package/dist/agent/memory/types.js +119 -0
- package/dist/agent/memory/types.js.map +1 -0
- package/dist/agent/memory/vault.d.ts +49 -0
- package/dist/agent/memory/vault.js +125 -0
- package/dist/agent/memory/vault.js.map +1 -0
- package/dist/agent/merchant/action-candidate.d.ts +106 -0
- package/dist/agent/merchant/action-candidate.js +241 -0
- package/dist/agent/merchant/action-candidate.js.map +1 -0
- package/dist/agent/merchant/credential-broker.d.ts +67 -0
- package/dist/agent/merchant/credential-broker.js +76 -0
- package/dist/agent/merchant/credential-broker.js.map +1 -0
- package/dist/agent/merchant/fake-merchant-client.d.ts +47 -0
- package/dist/agent/merchant/fake-merchant-client.js +143 -0
- package/dist/agent/merchant/fake-merchant-client.js.map +1 -0
- package/dist/agent/merchant/merchant-client.d.ts +49 -0
- package/dist/agent/merchant/merchant-client.js +186 -0
- package/dist/agent/merchant/merchant-client.js.map +1 -0
- package/dist/agent/merchant/merchant-tools.d.ts +74 -0
- package/dist/agent/merchant/merchant-tools.js +582 -0
- package/dist/agent/merchant/merchant-tools.js.map +1 -0
- package/dist/agent/merchant/types.d.ts +119 -0
- package/dist/agent/merchant/types.js +133 -0
- package/dist/agent/merchant/types.js.map +1 -0
- package/dist/agent/mode.d.ts +32 -0
- package/dist/agent/mode.js +34 -0
- package/dist/agent/mode.js.map +1 -0
- package/dist/agent/negotiation-chat.d.ts +81 -0
- package/dist/agent/negotiation-chat.js +330 -0
- package/dist/agent/negotiation-chat.js.map +1 -0
- package/dist/agent/session.d.ts +22 -0
- package/dist/agent/session.js +164 -0
- package/dist/agent/session.js.map +1 -0
- package/dist/agent/system-prompt.d.ts +26 -0
- package/dist/agent/system-prompt.js +77 -0
- package/dist/agent/system-prompt.js.map +1 -0
- package/dist/agent/write-gate.d.ts +98 -0
- package/dist/agent/write-gate.js +76 -0
- package/dist/agent/write-gate.js.map +1 -0
- package/dist/cli.d.ts +18 -0
- package/dist/cli.js +1139 -0
- package/dist/cli.js.map +1 -0
- package/dist/commerce/data-source.d.ts +88 -0
- package/dist/commerce/data-source.js +25 -0
- package/dist/commerce/data-source.js.map +1 -0
- package/dist/commerce/erp-source.d.ts +51 -0
- package/dist/commerce/erp-source.js +184 -0
- package/dist/commerce/erp-source.js.map +1 -0
- package/dist/commerce/fake-client.d.ts +167 -0
- package/dist/commerce/fake-client.js +549 -0
- package/dist/commerce/fake-client.js.map +1 -0
- package/dist/commerce/http-client.d.ts +73 -0
- package/dist/commerce/http-client.js +284 -0
- package/dist/commerce/http-client.js.map +1 -0
- package/dist/commerce/local-db-source.d.ts +50 -0
- package/dist/commerce/local-db-source.js +162 -0
- package/dist/commerce/local-db-source.js.map +1 -0
- package/dist/commerce/shopping-cli-source.d.ts +57 -0
- package/dist/commerce/shopping-cli-source.js +206 -0
- package/dist/commerce/shopping-cli-source.js.map +1 -0
- package/dist/commerce/types.d.ts +146 -0
- package/dist/commerce/types.js +31 -0
- package/dist/commerce/types.js.map +1 -0
- package/dist/config/profile.d.ts +122 -0
- package/dist/config/profile.js +386 -0
- package/dist/config/profile.js.map +1 -0
- package/dist/contracts/negotiation-schema.d.ts +28 -0
- package/dist/contracts/negotiation-schema.js +101 -0
- package/dist/contracts/negotiation-schema.js.map +1 -0
- package/dist/contracts/schemas.d.ts +31 -0
- package/dist/contracts/schemas.js +122 -0
- package/dist/contracts/schemas.js.map +1 -0
- package/dist/counterparty/a2a-direct/index.d.ts +41 -0
- package/dist/counterparty/a2a-direct/index.js +330 -0
- package/dist/counterparty/a2a-direct/index.js.map +1 -0
- package/dist/counterparty/channel.d.ts +200 -0
- package/dist/counterparty/channel.js +61 -0
- package/dist/counterparty/channel.js.map +1 -0
- package/dist/counterparty/index.d.ts +28 -0
- package/dist/counterparty/index.js +24 -0
- package/dist/counterparty/index.js.map +1 -0
- package/dist/counterparty/platform-api/index.d.ts +41 -0
- package/dist/counterparty/platform-api/index.js +65 -0
- package/dist/counterparty/platform-api/index.js.map +1 -0
- package/dist/counterparty/registry.d.ts +51 -0
- package/dist/counterparty/registry.js +71 -0
- package/dist/counterparty/registry.js.map +1 -0
- package/dist/counterparty/shopping-cli-hosted/index.d.ts +36 -0
- package/dist/counterparty/shopping-cli-hosted/index.js +337 -0
- package/dist/counterparty/shopping-cli-hosted/index.js.map +1 -0
- package/dist/discovery/agent-card/error.d.ts +28 -0
- package/dist/discovery/agent-card/error.js +31 -0
- package/dist/discovery/agent-card/error.js.map +1 -0
- package/dist/discovery/agent-card/extensions.d.ts +20 -0
- package/dist/discovery/agent-card/extensions.js +59 -0
- package/dist/discovery/agent-card/extensions.js.map +1 -0
- package/dist/discovery/agent-card/index.d.ts +29 -0
- package/dist/discovery/agent-card/index.js +38 -0
- package/dist/discovery/agent-card/index.js.map +1 -0
- package/dist/discovery/agent-card/secrets.d.ts +30 -0
- package/dist/discovery/agent-card/secrets.js +240 -0
- package/dist/discovery/agent-card/secrets.js.map +1 -0
- package/dist/discovery/agent-card/types.d.ts +110 -0
- package/dist/discovery/agent-card/types.js +37 -0
- package/dist/discovery/agent-card/types.js.map +1 -0
- package/dist/discovery/agent-card/validate.d.ts +31 -0
- package/dist/discovery/agent-card/validate.js +210 -0
- package/dist/discovery/agent-card/validate.js.map +1 -0
- package/dist/discovery/capability/error.d.ts +23 -0
- package/dist/discovery/capability/error.js +28 -0
- package/dist/discovery/capability/error.js.map +1 -0
- package/dist/discovery/capability/index.d.ts +21 -0
- package/dist/discovery/capability/index.js +21 -0
- package/dist/discovery/capability/index.js.map +1 -0
- package/dist/discovery/capability/intersect.d.ts +56 -0
- package/dist/discovery/capability/intersect.js +137 -0
- package/dist/discovery/capability/intersect.js.map +1 -0
- package/dist/discovery/catalog-source/errors.d.ts +32 -0
- package/dist/discovery/catalog-source/errors.js +41 -0
- package/dist/discovery/catalog-source/errors.js.map +1 -0
- package/dist/discovery/catalog-source/index.d.ts +30 -0
- package/dist/discovery/catalog-source/index.js +29 -0
- package/dist/discovery/catalog-source/index.js.map +1 -0
- package/dist/discovery/catalog-source/kiwi-record.d.ts +183 -0
- package/dist/discovery/catalog-source/kiwi-record.js +72 -0
- package/dist/discovery/catalog-source/kiwi-record.js.map +1 -0
- package/dist/discovery/catalog-source/kiwi-schema.d.ts +33 -0
- package/dist/discovery/catalog-source/kiwi-schema.js +106 -0
- package/dist/discovery/catalog-source/kiwi-schema.js.map +1 -0
- package/dist/discovery/catalog-source/kiwi-source.d.ts +38 -0
- package/dist/discovery/catalog-source/kiwi-source.js +318 -0
- package/dist/discovery/catalog-source/kiwi-source.js.map +1 -0
- package/dist/discovery/catalog-source/register.d.ts +48 -0
- package/dist/discovery/catalog-source/register.js +83 -0
- package/dist/discovery/catalog-source/register.js.map +1 -0
- package/dist/discovery/catalog-source/schema.d.ts +21 -0
- package/dist/discovery/catalog-source/schema.js +63 -0
- package/dist/discovery/catalog-source/schema.js.map +1 -0
- package/dist/discovery/catalog-source/source.d.ts +45 -0
- package/dist/discovery/catalog-source/source.js +197 -0
- package/dist/discovery/catalog-source/source.js.map +1 -0
- package/dist/discovery/catalog-source/types.d.ts +122 -0
- package/dist/discovery/catalog-source/types.js +30 -0
- package/dist/discovery/catalog-source/types.js.map +1 -0
- package/dist/discovery/index.d.ts +25 -0
- package/dist/discovery/index.js +25 -0
- package/dist/discovery/index.js.map +1 -0
- package/dist/discovery/resolve.d.ts +175 -0
- package/dist/discovery/resolve.js +367 -0
- package/dist/discovery/resolve.js.map +1 -0
- package/dist/discovery/ucp/error.d.ts +25 -0
- package/dist/discovery/ucp/error.js +27 -0
- package/dist/discovery/ucp/error.js.map +1 -0
- package/dist/discovery/ucp/index.d.ts +33 -0
- package/dist/discovery/ucp/index.js +28 -0
- package/dist/discovery/ucp/index.js.map +1 -0
- package/dist/discovery/ucp/intersect.d.ts +148 -0
- package/dist/discovery/ucp/intersect.js +312 -0
- package/dist/discovery/ucp/intersect.js.map +1 -0
- package/dist/discovery/ucp/resolver.d.ts +62 -0
- package/dist/discovery/ucp/resolver.js +214 -0
- package/dist/discovery/ucp/resolver.js.map +1 -0
- package/dist/discovery/ucp/types.d.ts +97 -0
- package/dist/discovery/ucp/types.js +103 -0
- package/dist/discovery/ucp/types.js.map +1 -0
- package/dist/discovery/ucp/validate.d.ts +38 -0
- package/dist/discovery/ucp/validate.js +232 -0
- package/dist/discovery/ucp/validate.js.map +1 -0
- package/dist/discovery/ucp/vendor.d.ts +60 -0
- package/dist/discovery/ucp/vendor.js +61 -0
- package/dist/discovery/ucp/vendor.js.map +1 -0
- package/dist/doctor.d.ts +26 -0
- package/dist/doctor.js +113 -0
- package/dist/doctor.js.map +1 -0
- package/dist/exit-codes.d.ts +26 -0
- package/dist/exit-codes.js +27 -0
- package/dist/exit-codes.js.map +1 -0
- package/dist/fanout/disclosure.d.ts +138 -0
- package/dist/fanout/disclosure.js +188 -0
- package/dist/fanout/disclosure.js.map +1 -0
- package/dist/fanout/index.d.ts +32 -0
- package/dist/fanout/index.js +30 -0
- package/dist/fanout/index.js.map +1 -0
- package/dist/fanout/orchestrator.d.ts +153 -0
- package/dist/fanout/orchestrator.js +439 -0
- package/dist/fanout/orchestrator.js.map +1 -0
- package/dist/fanout/policy.d.ts +128 -0
- package/dist/fanout/policy.js +130 -0
- package/dist/fanout/policy.js.map +1 -0
- package/dist/handoff/acp-commerce.d.ts +58 -0
- package/dist/handoff/acp-commerce.js +69 -0
- package/dist/handoff/acp-commerce.js.map +1 -0
- package/dist/handoff/authorization.d.ts +127 -0
- package/dist/handoff/authorization.js +107 -0
- package/dist/handoff/authorization.js.map +1 -0
- package/dist/handoff/candidate.d.ts +94 -0
- package/dist/handoff/candidate.js +172 -0
- package/dist/handoff/candidate.js.map +1 -0
- package/dist/handoff/channel.d.ts +88 -0
- package/dist/handoff/channel.js +189 -0
- package/dist/handoff/channel.js.map +1 -0
- package/dist/handoff/completion.d.ts +44 -0
- package/dist/handoff/completion.js +136 -0
- package/dist/handoff/completion.js.map +1 -0
- package/dist/handoff/delivery.d.ts +59 -0
- package/dist/handoff/delivery.js +185 -0
- package/dist/handoff/delivery.js.map +1 -0
- package/dist/handoff/destination.d.ts +39 -0
- package/dist/handoff/destination.js +99 -0
- package/dist/handoff/destination.js.map +1 -0
- package/dist/handoff/errors.d.ts +34 -0
- package/dist/handoff/errors.js +47 -0
- package/dist/handoff/errors.js.map +1 -0
- package/dist/handoff/idempotency.d.ts +51 -0
- package/dist/handoff/idempotency.js +168 -0
- package/dist/handoff/idempotency.js.map +1 -0
- package/dist/handoff/index.d.ts +46 -0
- package/dist/handoff/index.js +48 -0
- package/dist/handoff/index.js.map +1 -0
- package/dist/handoff/ledger.d.ts +94 -0
- package/dist/handoff/ledger.js +195 -0
- package/dist/handoff/ledger.js.map +1 -0
- package/dist/handoff/lifecycle.d.ts +29 -0
- package/dist/handoff/lifecycle.js +102 -0
- package/dist/handoff/lifecycle.js.map +1 -0
- package/dist/handoff/metrics.d.ts +56 -0
- package/dist/handoff/metrics.js +78 -0
- package/dist/handoff/metrics.js.map +1 -0
- package/dist/handoff/operator-approval.d.ts +143 -0
- package/dist/handoff/operator-approval.js +287 -0
- package/dist/handoff/operator-approval.js.map +1 -0
- package/dist/handoff/order-record.d.ts +104 -0
- package/dist/handoff/order-record.js +235 -0
- package/dist/handoff/order-record.js.map +1 -0
- package/dist/handoff/package.d.ts +102 -0
- package/dist/handoff/package.js +132 -0
- package/dist/handoff/package.js.map +1 -0
- package/dist/handoff/transaction.d.ts +96 -0
- package/dist/handoff/transaction.js +263 -0
- package/dist/handoff/transaction.js.map +1 -0
- package/dist/handoff/ucp-checkout/cart-channel.d.ts +111 -0
- package/dist/handoff/ucp-checkout/cart-channel.js +370 -0
- package/dist/handoff/ucp-checkout/cart-channel.js.map +1 -0
- package/dist/handoff/ucp-checkout/cart-parse.d.ts +22 -0
- package/dist/handoff/ucp-checkout/cart-parse.js +102 -0
- package/dist/handoff/ucp-checkout/cart-parse.js.map +1 -0
- package/dist/handoff/ucp-checkout/cart-types.d.ts +93 -0
- package/dist/handoff/ucp-checkout/cart-types.js +38 -0
- package/dist/handoff/ucp-checkout/cart-types.js.map +1 -0
- package/dist/handoff/ucp-checkout/channel.d.ts +159 -0
- package/dist/handoff/ucp-checkout/channel.js +636 -0
- package/dist/handoff/ucp-checkout/channel.js.map +1 -0
- package/dist/handoff/ucp-checkout/client.d.ts +88 -0
- package/dist/handoff/ucp-checkout/client.js +228 -0
- package/dist/handoff/ucp-checkout/client.js.map +1 -0
- package/dist/handoff/ucp-checkout/endpoint.d.ts +36 -0
- package/dist/handoff/ucp-checkout/endpoint.js +145 -0
- package/dist/handoff/ucp-checkout/endpoint.js.map +1 -0
- package/dist/handoff/ucp-checkout/index.d.ts +35 -0
- package/dist/handoff/ucp-checkout/index.js +36 -0
- package/dist/handoff/ucp-checkout/index.js.map +1 -0
- package/dist/handoff/ucp-checkout/parse.d.ts +71 -0
- package/dist/handoff/ucp-checkout/parse.js +349 -0
- package/dist/handoff/ucp-checkout/parse.js.map +1 -0
- package/dist/handoff/ucp-checkout/totals.d.ts +41 -0
- package/dist/handoff/ucp-checkout/totals.js +36 -0
- package/dist/handoff/ucp-checkout/totals.js.map +1 -0
- package/dist/handoff/ucp-checkout/types.d.ts +149 -0
- package/dist/handoff/ucp-checkout/types.js +58 -0
- package/dist/handoff/ucp-checkout/types.js.map +1 -0
- package/dist/handoff/url-safety.d.ts +44 -0
- package/dist/handoff/url-safety.js +121 -0
- package/dist/handoff/url-safety.js.map +1 -0
- package/dist/i18n.d.ts +24 -0
- package/dist/i18n.js +27 -0
- package/dist/i18n.js.map +1 -0
- package/dist/negotiation/action-candidate.d.ts +97 -0
- package/dist/negotiation/action-candidate.js +160 -0
- package/dist/negotiation/action-candidate.js.map +1 -0
- package/dist/negotiation/condition/evaluator.d.ts +36 -0
- package/dist/negotiation/condition/evaluator.js +123 -0
- package/dist/negotiation/condition/evaluator.js.map +1 -0
- package/dist/negotiation/context-map/index.d.ts +23 -0
- package/dist/negotiation/context-map/index.js +22 -0
- package/dist/negotiation/context-map/index.js.map +1 -0
- package/dist/negotiation/context-map/store.d.ts +51 -0
- package/dist/negotiation/context-map/store.js +186 -0
- package/dist/negotiation/context-map/store.js.map +1 -0
- package/dist/negotiation/context-map/types.d.ts +29 -0
- package/dist/negotiation/context-map/types.js +57 -0
- package/dist/negotiation/context-map/types.js.map +1 -0
- package/dist/negotiation/domain/common.d.ts +95 -0
- package/dist/negotiation/domain/common.js +216 -0
- package/dist/negotiation/domain/common.js.map +1 -0
- package/dist/negotiation/domain/envelope.d.ts +55 -0
- package/dist/negotiation/domain/envelope.js +110 -0
- package/dist/negotiation/domain/envelope.js.map +1 -0
- package/dist/negotiation/domain/identifiers.d.ts +65 -0
- package/dist/negotiation/domain/identifiers.js +130 -0
- package/dist/negotiation/domain/identifiers.js.map +1 -0
- package/dist/negotiation/domain/objects.d.ts +149 -0
- package/dist/negotiation/domain/objects.js +335 -0
- package/dist/negotiation/domain/objects.js.map +1 -0
- package/dist/negotiation/idempotency/index.d.ts +26 -0
- package/dist/negotiation/idempotency/index.js +25 -0
- package/dist/negotiation/idempotency/index.js.map +1 -0
- package/dist/negotiation/idempotency/store.d.ts +52 -0
- package/dist/negotiation/idempotency/store.js +189 -0
- package/dist/negotiation/idempotency/store.js.map +1 -0
- package/dist/negotiation/idempotency/types.d.ts +102 -0
- package/dist/negotiation/idempotency/types.js +47 -0
- package/dist/negotiation/idempotency/types.js.map +1 -0
- package/dist/negotiation/jcs.d.ts +21 -0
- package/dist/negotiation/jcs.js +114 -0
- package/dist/negotiation/jcs.js.map +1 -0
- package/dist/negotiation/ledger/event.d.ts +142 -0
- package/dist/negotiation/ledger/event.js +206 -0
- package/dist/negotiation/ledger/event.js.map +1 -0
- package/dist/negotiation/ledger/index.d.ts +26 -0
- package/dist/negotiation/ledger/index.js +25 -0
- package/dist/negotiation/ledger/index.js.map +1 -0
- package/dist/negotiation/ledger/store.d.ts +97 -0
- package/dist/negotiation/ledger/store.js +338 -0
- package/dist/negotiation/ledger/store.js.map +1 -0
- package/dist/negotiation/prompt.d.ts +34 -0
- package/dist/negotiation/prompt.js +113 -0
- package/dist/negotiation/prompt.js.map +1 -0
- package/dist/negotiation/recovery/index.d.ts +26 -0
- package/dist/negotiation/recovery/index.js +24 -0
- package/dist/negotiation/recovery/index.js.map +1 -0
- package/dist/negotiation/recovery/outbound.d.ts +49 -0
- package/dist/negotiation/recovery/outbound.js +34 -0
- package/dist/negotiation/recovery/outbound.js.map +1 -0
- package/dist/negotiation/recovery/recover.d.ts +59 -0
- package/dist/negotiation/recovery/recover.js +486 -0
- package/dist/negotiation/recovery/recover.js.map +1 -0
- package/dist/negotiation/recovery/types.d.ts +85 -0
- package/dist/negotiation/recovery/types.js +17 -0
- package/dist/negotiation/recovery/types.js.map +1 -0
- package/dist/negotiation/state/phase.d.ts +70 -0
- package/dist/negotiation/state/phase.js +200 -0
- package/dist/negotiation/state/phase.js.map +1 -0
- package/dist/negotiation/types.d.ts +139 -0
- package/dist/negotiation/types.js +24 -0
- package/dist/negotiation/types.js.map +1 -0
- package/dist/net/safe-http.d.ts +54 -0
- package/dist/net/safe-http.js +116 -0
- package/dist/net/safe-http.js.map +1 -0
- package/dist/operator/controller.d.ts +181 -0
- package/dist/operator/controller.js +784 -0
- package/dist/operator/controller.js.map +1 -0
- package/dist/operator/runner.d.ts +128 -0
- package/dist/operator/runner.js +248 -0
- package/dist/operator/runner.js.map +1 -0
- package/dist/operator/store.d.ts +39 -0
- package/dist/operator/store.js +169 -0
- package/dist/operator/store.js.map +1 -0
- package/dist/operator/strategy.d.ts +54 -0
- package/dist/operator/strategy.js +249 -0
- package/dist/operator/strategy.js.map +1 -0
- package/dist/operator/tui.d.ts +27 -0
- package/dist/operator/tui.js +395 -0
- package/dist/operator/tui.js.map +1 -0
- package/dist/operator/types.d.ts +224 -0
- package/dist/operator/types.js +17 -0
- package/dist/operator/types.js.map +1 -0
- package/dist/product-buyer.d.ts +74 -0
- package/dist/product-buyer.js +161 -0
- package/dist/product-buyer.js.map +1 -0
- package/dist/product-cli.d.ts +56 -0
- package/dist/product-cli.js +175 -0
- package/dist/product-cli.js.map +1 -0
- package/dist/product-compat.d.ts +50 -0
- package/dist/product-compat.js +63 -0
- package/dist/product-compat.js.map +1 -0
- package/dist/product-init.d.ts +73 -0
- package/dist/product-init.js +203 -0
- package/dist/product-init.js.map +1 -0
- package/dist/product-publish.d.ts +85 -0
- package/dist/product-publish.js +216 -0
- package/dist/product-publish.js.map +1 -0
- package/dist/protocol/legacy-shopping-negotiation/adapter.d.ts +42 -0
- package/dist/protocol/legacy-shopping-negotiation/adapter.js +561 -0
- package/dist/protocol/legacy-shopping-negotiation/adapter.js.map +1 -0
- package/dist/protocol/legacy-shopping-negotiation/mapping.d.ts +78 -0
- package/dist/protocol/legacy-shopping-negotiation/mapping.js +321 -0
- package/dist/protocol/legacy-shopping-negotiation/mapping.js.map +1 -0
- package/dist/protocol/legacy-shopping-negotiation/money.d.ts +49 -0
- package/dist/protocol/legacy-shopping-negotiation/money.js +70 -0
- package/dist/protocol/legacy-shopping-negotiation/money.js.map +1 -0
- package/dist/protocol/legacy-shopping-negotiation/types.d.ts +107 -0
- package/dist/protocol/legacy-shopping-negotiation/types.js +34 -0
- package/dist/protocol/legacy-shopping-negotiation/types.js.map +1 -0
- package/dist/runtime/buyer-policy.d.ts +58 -0
- package/dist/runtime/buyer-policy.js +89 -0
- package/dist/runtime/buyer-policy.js.map +1 -0
- package/dist/runtime/fake-model.d.ts +77 -0
- package/dist/runtime/fake-model.js +307 -0
- package/dist/runtime/fake-model.js.map +1 -0
- package/dist/runtime/foreground.d.ts +56 -0
- package/dist/runtime/foreground.js +97 -0
- package/dist/runtime/foreground.js.map +1 -0
- package/dist/runtime/heartbeat.d.ts +36 -0
- package/dist/runtime/heartbeat.js +49 -0
- package/dist/runtime/heartbeat.js.map +1 -0
- package/dist/runtime/merchant-turn.d.ts +35 -0
- package/dist/runtime/merchant-turn.js +20 -0
- package/dist/runtime/merchant-turn.js.map +1 -0
- package/dist/runtime/model.d.ts +40 -0
- package/dist/runtime/model.js +86 -0
- package/dist/runtime/model.js.map +1 -0
- package/dist/runtime/negotiation-turn.d.ts +101 -0
- package/dist/runtime/negotiation-turn.js +317 -0
- package/dist/runtime/negotiation-turn.js.map +1 -0
- package/dist/runtime/tools.d.ts +64 -0
- package/dist/runtime/tools.js +236 -0
- package/dist/runtime/tools.js.map +1 -0
- package/dist/supervisor/init.d.ts +31 -0
- package/dist/supervisor/init.js +222 -0
- package/dist/supervisor/init.js.map +1 -0
- package/dist/supervisor/logs.d.ts +28 -0
- package/dist/supervisor/logs.js +101 -0
- package/dist/supervisor/logs.js.map +1 -0
- package/dist/supervisor/manage.d.ts +72 -0
- package/dist/supervisor/manage.js +419 -0
- package/dist/supervisor/manage.js.map +1 -0
- package/dist/supervisor/manifest.d.ts +69 -0
- package/dist/supervisor/manifest.js +209 -0
- package/dist/supervisor/manifest.js.map +1 -0
- package/dist/supervisor/stack-config.d.ts +79 -0
- package/dist/supervisor/stack-config.js +262 -0
- package/dist/supervisor/stack-config.js.map +1 -0
- package/dist/supervisor/wrapper.d.ts +17 -0
- package/dist/supervisor/wrapper.js +138 -0
- package/dist/supervisor/wrapper.js.map +1 -0
- package/dist/trust/identity/auth-verifier.d.ts +96 -0
- package/dist/trust/identity/auth-verifier.js +166 -0
- package/dist/trust/identity/auth-verifier.js.map +1 -0
- package/dist/trust/identity/identity-binding.d.ts +63 -0
- package/dist/trust/identity/identity-binding.js +59 -0
- package/dist/trust/identity/identity-binding.js.map +1 -0
- package/dist/trust/identity/index.d.ts +38 -0
- package/dist/trust/identity/index.js +31 -0
- package/dist/trust/identity/index.js.map +1 -0
- package/dist/trust/identity/jws.d.ts +64 -0
- package/dist/trust/identity/jws.js +178 -0
- package/dist/trust/identity/jws.js.map +1 -0
- package/dist/trust/identity/keys.d.ts +71 -0
- package/dist/trust/identity/keys.js +118 -0
- package/dist/trust/identity/keys.js.map +1 -0
- package/dist/trust/identity/message-signature.d.ts +105 -0
- package/dist/trust/identity/message-signature.js +297 -0
- package/dist/trust/identity/message-signature.js.map +1 -0
- package/dist/trust/identity/nonce.d.ts +45 -0
- package/dist/trust/identity/nonce.js +50 -0
- package/dist/trust/identity/nonce.js.map +1 -0
- package/dist/trust/identity/signature-base.d.ts +84 -0
- package/dist/trust/identity/signature-base.js +261 -0
- package/dist/trust/identity/signature-base.js.map +1 -0
- package/dist/trust/identity/trust-policy.d.ts +92 -0
- package/dist/trust/identity/trust-policy.js +95 -0
- package/dist/trust/identity/trust-policy.js.map +1 -0
- package/dist/trust/index.d.ts +21 -0
- package/dist/trust/index.js +22 -0
- package/dist/trust/index.js.map +1 -0
- package/dist/trust/records/evaluator.d.ts +76 -0
- package/dist/trust/records/evaluator.js +122 -0
- package/dist/trust/records/evaluator.js.map +1 -0
- package/dist/trust/records/index.d.ts +28 -0
- package/dist/trust/records/index.js +26 -0
- package/dist/trust/records/index.js.map +1 -0
- package/dist/trust/records/store.d.ts +75 -0
- package/dist/trust/records/store.js +339 -0
- package/dist/trust/records/store.js.map +1 -0
- package/dist/trust/records/types.d.ts +159 -0
- package/dist/trust/records/types.js +40 -0
- package/dist/trust/records/types.js.map +1 -0
- package/dist/tui/banner.d.ts +46 -0
- package/dist/tui/banner.js +99 -0
- package/dist/tui/banner.js.map +1 -0
- package/dist/tui/styles.d.ts +70 -0
- package/dist/tui/styles.js +197 -0
- package/dist/tui/styles.js.map +1 -0
- package/dist/tui/theme.d.ts +63 -0
- package/dist/tui/theme.js +136 -0
- package/dist/tui/theme.js.map +1 -0
- package/examples/profiles/buyer.deepseek.yaml +34 -0
- package/examples/profiles/buyer.fake.yaml +36 -0
- package/examples/profiles/buyer.local.yaml +40 -0
- package/examples/profiles/merchant.deepseek.yaml +32 -0
- package/examples/profiles/merchant.fake.yaml +31 -0
- package/examples/profiles/merchant.local.yaml +34 -0
- package/package.json +55 -0
|
@@ -0,0 +1,881 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026 harrylabsj
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
import { uuidv7 } from "@earendil-works/pi-ai";
|
|
17
|
+
import { isMemoryNamespace, isMemorySensitivity, isMemorySourceKind, isRetrievalPurpose, isVaultKind, MemoryError, parseMemoryScope, } from "./types.js";
|
|
18
|
+
import { VaultKeyError } from "./vault.js";
|
|
19
|
+
import { MEMORY_SCHEMA_VERSION } from "./schema.js";
|
|
20
|
+
const SOURCE_WEIGHT = {
|
|
21
|
+
explicit: 1.0,
|
|
22
|
+
observed: 0.8,
|
|
23
|
+
inferred: 0.6,
|
|
24
|
+
imported: 0.7,
|
|
25
|
+
};
|
|
26
|
+
const DEFAULT_CONFIDENCE = {
|
|
27
|
+
explicit: 1.0,
|
|
28
|
+
observed: 0.5,
|
|
29
|
+
inferred: 0.3,
|
|
30
|
+
imported: 0.6,
|
|
31
|
+
};
|
|
32
|
+
/** Soft namespaces that repeated behavior may activate without confirmation. */
|
|
33
|
+
const SOFT_ACTIVATABLE = new Set(["preference", "routine"]);
|
|
34
|
+
const AUTO_ACTIVATE_EVIDENCE = 3;
|
|
35
|
+
const MAX_LIMIT = 32;
|
|
36
|
+
/**
|
|
37
|
+
* High-impact memories must never be auto-activated by a model `remember`
|
|
38
|
+
* call: a hard `constraint` and any `restricted` value stay `candidate` until
|
|
39
|
+
* the human confirms via `/confirm` (design §10.1/§16). The model asserting
|
|
40
|
+
* `explicit_user_statement` is not ground truth — only a human can promote.
|
|
41
|
+
*/
|
|
42
|
+
function requiresHumanConfirm(input) {
|
|
43
|
+
return input.namespace === "constraint" || input.sensitivity === "restricted";
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Restricted writes: never let the plaintext echo into evidence summaries or
|
|
47
|
+
* audit reasons (design §6.3 minimal disclosure). The whole-DB plaintext-free
|
|
48
|
+
* guarantee only holds if the model-supplied summary is scrubbed too.
|
|
49
|
+
*/
|
|
50
|
+
function evidenceSummaryFor(input, summary) {
|
|
51
|
+
if (input.sensitivity !== "restricted" || input.restricted === undefined)
|
|
52
|
+
return summary;
|
|
53
|
+
const plaintext = input.restricted.plaintext;
|
|
54
|
+
const scrubbed = plaintext !== "" ? summary.split(plaintext).join("…") : summary;
|
|
55
|
+
return scrubbed.trim() !== "" ? scrubbed : "用户确认的敏感信息(已加密保存)";
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Precise personal data must live in the Vault regardless of the sensitivity
|
|
59
|
+
* the model happened to claim (design §6.3, §17). A string value that clearly
|
|
60
|
+
* matches one of these patterns is escalated to `restricted`; if that then
|
|
61
|
+
* fails the Restricted validation (no explicit statement, no data key) the
|
|
62
|
+
* write is refused — never degraded to plaintext.
|
|
63
|
+
*/
|
|
64
|
+
const PRECISE_PERSONAL_PATTERNS = [
|
|
65
|
+
{
|
|
66
|
+
kind: "address",
|
|
67
|
+
pattern: /(住址|地址|收货|寄到|家庭住址|住在|家住)[^,。;;]{0,20}\d|(?:省|市|区|县|镇|街道).{0,12}(?:号|路|小区|巷)[\d一二三四五六七八九十]*/,
|
|
68
|
+
},
|
|
69
|
+
{ kind: "contact", pattern: /(电话|手机|手机号|微信号|联系方式|邮箱|e-?mail|QQ)\s*[::]?[\s-]*\d{5,}/i },
|
|
70
|
+
{ kind: "private_budget", pattern: /(预算|心理价|心理价位|最高出价|上限价)\s*[::]?\s*(\d+)/ },
|
|
71
|
+
{ kind: "merchant_cost", pattern: /(成本|进价)\s*[::]?\s*(\d+)/ },
|
|
72
|
+
{ kind: "merchant_floor", pattern: /(底价|最低价|最低售价)\s*[::]?\s*(\d+)/ },
|
|
73
|
+
{ kind: "other", pattern: /(身份证|银行卡|银行账号|护照|护照号|卡号|账号)\s*[::]?[\dXx]/i },
|
|
74
|
+
];
|
|
75
|
+
function classifyPersonalData(value) {
|
|
76
|
+
for (const { kind, pattern } of PRECISE_PERSONAL_PATTERNS) {
|
|
77
|
+
if (pattern.test(value))
|
|
78
|
+
return kind;
|
|
79
|
+
}
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Escalate a string value that clearly is precise personal data to a
|
|
84
|
+
* Restricted (Vault) write. Object/array values are left alone — a structured
|
|
85
|
+
* value is the model's explicit non-Restricted choice, not a raw secret.
|
|
86
|
+
*/
|
|
87
|
+
function escalateSensitivity(input) {
|
|
88
|
+
if (input.sensitivity === "restricted")
|
|
89
|
+
return input;
|
|
90
|
+
if (input.value === undefined || typeof input.value !== "string")
|
|
91
|
+
return input;
|
|
92
|
+
const kind = classifyPersonalData(input.value);
|
|
93
|
+
if (kind === undefined)
|
|
94
|
+
return input;
|
|
95
|
+
return {
|
|
96
|
+
...input,
|
|
97
|
+
sensitivity: "restricted",
|
|
98
|
+
restricted: { kind, plaintext: input.value },
|
|
99
|
+
value: undefined,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function optText(value) {
|
|
103
|
+
return value === null ? undefined : value;
|
|
104
|
+
}
|
|
105
|
+
function assertJsonValue(value, at) {
|
|
106
|
+
if (value === undefined)
|
|
107
|
+
return;
|
|
108
|
+
if (typeof value === "number" && !Number.isFinite(value)) {
|
|
109
|
+
throw new MemoryError("validation", `${at}: NaN/Infinity are not storable`);
|
|
110
|
+
}
|
|
111
|
+
if (Array.isArray(value)) {
|
|
112
|
+
for (let i = 0; i < value.length; i++)
|
|
113
|
+
assertJsonValue(value[i], `${at}[${i}]`);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (value !== null && typeof value === "object") {
|
|
117
|
+
for (const [k, v] of Object.entries(value)) {
|
|
118
|
+
assertJsonValue(v, `${at}.${k}`);
|
|
119
|
+
}
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (typeof value !== "string" && typeof value !== "number" && typeof value !== "boolean" && value !== null) {
|
|
123
|
+
throw new MemoryError("validation", `${at}: unsupported value type`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/** Redacted snapshot of an item for audit events — never Restricted plaintext. */
|
|
127
|
+
function auditSnapshot(item) {
|
|
128
|
+
return {
|
|
129
|
+
memory_id: item.memory_id,
|
|
130
|
+
namespace: item.namespace,
|
|
131
|
+
key: item.key,
|
|
132
|
+
value: item.vault_ref !== undefined ? "[vault]" : item.value,
|
|
133
|
+
scope: item.scope,
|
|
134
|
+
source_kind: item.source_kind,
|
|
135
|
+
confidence: item.confidence,
|
|
136
|
+
sensitivity: item.sensitivity,
|
|
137
|
+
status: item.status,
|
|
138
|
+
version: item.version,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
export class MemoryStore {
|
|
142
|
+
db;
|
|
143
|
+
vault;
|
|
144
|
+
now;
|
|
145
|
+
constructor(options) {
|
|
146
|
+
this.db = options.db;
|
|
147
|
+
this.vault = options.vault;
|
|
148
|
+
// Normalize to UTC ISO (lexicographic timestamp comparisons in SQLite).
|
|
149
|
+
const clock = options.now ?? (() => new Date().toISOString());
|
|
150
|
+
this.now = () => new Date(Date.parse(clock())).toISOString();
|
|
151
|
+
}
|
|
152
|
+
// ---- principals ---------------------------------------------------------
|
|
153
|
+
/** Create or return the principal. Role and owner are immutable — mismatch fails closed. */
|
|
154
|
+
ensurePrincipal(input) {
|
|
155
|
+
const existing = this.getPrincipal(input.principal_id);
|
|
156
|
+
const now = this.now();
|
|
157
|
+
if (existing !== undefined) {
|
|
158
|
+
if (existing.role !== input.role || existing.owner_id !== input.owner_id) {
|
|
159
|
+
throw new MemoryError("conflict", `principal ${input.principal_id} is bound to ${existing.role}/${existing.owner_id}; ` +
|
|
160
|
+
`role and owner are immutable (physical isolation between agents)`);
|
|
161
|
+
}
|
|
162
|
+
return existing;
|
|
163
|
+
}
|
|
164
|
+
// One principal per agent database (design §17): a database that already
|
|
165
|
+
// belongs to another principal can never adopt a second identity.
|
|
166
|
+
const other = this.db.prepare("SELECT principal_id FROM principals LIMIT 1").get();
|
|
167
|
+
if (other !== undefined) {
|
|
168
|
+
throw new MemoryError("conflict", `this memory database belongs to ${other.principal_id}; ` +
|
|
169
|
+
`physical isolation between agents forbids binding ${input.principal_id}`);
|
|
170
|
+
}
|
|
171
|
+
this.db
|
|
172
|
+
.prepare(`INSERT INTO principals
|
|
173
|
+
(principal_id, owner_id, role, display_name, locale, timezone, memory_schema_version, created_at, updated_at)
|
|
174
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
175
|
+
.run(input.principal_id, input.owner_id, input.role, input.display_name ?? null, input.locale ?? "zh-CN", input.timezone ?? "Asia/Shanghai", MEMORY_SCHEMA_VERSION, now, now);
|
|
176
|
+
return this.getPrincipal(input.principal_id);
|
|
177
|
+
}
|
|
178
|
+
getPrincipal(principalId) {
|
|
179
|
+
const row = this.db
|
|
180
|
+
.prepare("SELECT * FROM principals WHERE principal_id = ?")
|
|
181
|
+
.get(principalId);
|
|
182
|
+
if (row === undefined)
|
|
183
|
+
return undefined;
|
|
184
|
+
return {
|
|
185
|
+
principal_id: row.principal_id,
|
|
186
|
+
owner_id: row.owner_id,
|
|
187
|
+
role: row.role,
|
|
188
|
+
display_name: row.display_name ?? undefined,
|
|
189
|
+
locale: row.locale,
|
|
190
|
+
timezone: row.timezone,
|
|
191
|
+
memory_schema_version: row.memory_schema_version,
|
|
192
|
+
created_at: row.created_at,
|
|
193
|
+
updated_at: row.updated_at,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
// ---- write path ---------------------------------------------------------
|
|
197
|
+
remember(input) {
|
|
198
|
+
// Precise personal data escalates to the Vault before validation, so a
|
|
199
|
+
// model mislabeling an address as `private`/`normal` is still sealed.
|
|
200
|
+
const effective = escalateSensitivity(input);
|
|
201
|
+
this.validateRemember(effective);
|
|
202
|
+
const now = this.now();
|
|
203
|
+
this.db.exec("BEGIN");
|
|
204
|
+
try {
|
|
205
|
+
const outcome = this.rememberTx(effective, now);
|
|
206
|
+
this.db.exec("COMMIT");
|
|
207
|
+
return outcome;
|
|
208
|
+
}
|
|
209
|
+
catch (err) {
|
|
210
|
+
this.db.exec("ROLLBACK");
|
|
211
|
+
if (err instanceof MemoryError || err instanceof VaultKeyError)
|
|
212
|
+
throw err;
|
|
213
|
+
throw new MemoryError("validation", err instanceof Error ? err.message : String(err));
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
validateRemember(input) {
|
|
217
|
+
if (!isMemoryNamespace(input.namespace)) {
|
|
218
|
+
throw new MemoryError("validation", `unknown namespace: ${String(input.namespace)}`);
|
|
219
|
+
}
|
|
220
|
+
if (typeof input.key !== "string" || input.key.length === 0 || input.key.length > 160) {
|
|
221
|
+
throw new MemoryError("validation", "key must be a non-empty string (<= 160 chars)");
|
|
222
|
+
}
|
|
223
|
+
if (!isMemorySourceKind(input.source_kind)) {
|
|
224
|
+
throw new MemoryError("validation", `unknown source_kind: ${String(input.source_kind)}`);
|
|
225
|
+
}
|
|
226
|
+
if (!isMemorySensitivity(input.sensitivity)) {
|
|
227
|
+
throw new MemoryError("validation", `unknown sensitivity: ${String(input.sensitivity)}`);
|
|
228
|
+
}
|
|
229
|
+
if ((input.value === undefined) === (input.restricted === undefined)) {
|
|
230
|
+
throw new MemoryError("validation", "exactly one of value / restricted must be provided (value_json and vault_ref are mutually exclusive)");
|
|
231
|
+
}
|
|
232
|
+
assertJsonValue(input.value, "value");
|
|
233
|
+
parseMemoryScope(input.scope);
|
|
234
|
+
if (input.namespace === "constraint" && input.source_kind !== "explicit") {
|
|
235
|
+
throw new MemoryError("validation", "hard constraints require an explicit source; inferred/observed signals can never become constraints");
|
|
236
|
+
}
|
|
237
|
+
if (input.sensitivity === "restricted") {
|
|
238
|
+
if (input.restricted === undefined) {
|
|
239
|
+
throw new MemoryError("validation", "restricted memories must carry a Vault plaintext");
|
|
240
|
+
}
|
|
241
|
+
if (!isVaultKind(input.restricted.kind)) {
|
|
242
|
+
throw new MemoryError("validation", `unknown vault kind: ${String(input.restricted.kind)}`);
|
|
243
|
+
}
|
|
244
|
+
if (input.source_kind !== "explicit") {
|
|
245
|
+
throw new MemoryError("validation", "Restricted memories require an explicit source (or a user-confirmed candidate)");
|
|
246
|
+
}
|
|
247
|
+
if (!input.explicit_user_statement) {
|
|
248
|
+
throw new MemoryError("validation", "Restricted memories require an explicit user statement");
|
|
249
|
+
}
|
|
250
|
+
if (!this.vault.available) {
|
|
251
|
+
throw new MemoryError("vault_unavailable", "no data key configured (KIWI_DATA_KEY); refusing Restricted write (fail closed)");
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
if (input.restricted !== undefined && input.sensitivity !== "restricted") {
|
|
255
|
+
throw new MemoryError("validation", "a Vault plaintext requires sensitivity=restricted");
|
|
256
|
+
}
|
|
257
|
+
if (input.expires_at !== undefined) {
|
|
258
|
+
if (Number.isNaN(Date.parse(input.expires_at))) {
|
|
259
|
+
throw new MemoryError("validation", "expires_at must be an RFC3339 timestamp");
|
|
260
|
+
}
|
|
261
|
+
// Normalize to UTC ISO: expireDue compares lexicographically against a
|
|
262
|
+
// UTC-Z now, so a "+08:00" input would otherwise silently never expire.
|
|
263
|
+
input.expires_at = new Date(Date.parse(input.expires_at)).toISOString();
|
|
264
|
+
}
|
|
265
|
+
if (input.confidence !== undefined && (input.confidence < 0 || input.confidence > 1)) {
|
|
266
|
+
throw new MemoryError("validation", "confidence must be in [0, 1]");
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
rememberTx(input, now) {
|
|
270
|
+
const principal = this.requirePrincipal();
|
|
271
|
+
const scope = parseMemoryScope(input.scope);
|
|
272
|
+
const existing = this.findLiveByKey(principal.principal_id, input.namespace, input.key, scope);
|
|
273
|
+
if (existing !== undefined) {
|
|
274
|
+
return this.mergeOrConflict(existing, input, scope, now);
|
|
275
|
+
}
|
|
276
|
+
// Constraint/restricted memories can never auto-activate from a model
|
|
277
|
+
// remember call — they stay candidate until the human /confirms them.
|
|
278
|
+
const explicitConfirmed = input.explicit_user_statement && !requiresHumanConfirm(input);
|
|
279
|
+
const status = explicitConfirmed ? "active" : "candidate";
|
|
280
|
+
const confidence = explicitConfirmed
|
|
281
|
+
? 1.0
|
|
282
|
+
: (input.confidence ?? DEFAULT_CONFIDENCE[input.source_kind]);
|
|
283
|
+
const item = this.insertItem(principal.principal_id, input, scope, status, confidence, explicitConfirmed ? now : undefined, now);
|
|
284
|
+
this.addEvidenceTx(item.memory_id, { ...input.evidence, polarity: "support", summary: evidenceSummaryFor(input, input.evidence.summary) }, now, true);
|
|
285
|
+
this.appendEvent(item.memory_id, explicitConfirmed ? "memory.confirmed" : "memory.proposed", input.actor, undefined, { after: auditSnapshot({ ...item, evidence_count: 1 }) }, now);
|
|
286
|
+
return { kind: explicitConfirmed ? "active" : "candidate", memory: { ...item, evidence_count: 1 } };
|
|
287
|
+
}
|
|
288
|
+
/** Same live (namespace, key, scope): merge evidence or handle a value conflict. */
|
|
289
|
+
mergeOrConflict(existing, input, scope, now) {
|
|
290
|
+
const sameValue = existing.vault_ref === undefined &&
|
|
291
|
+
input.restricted === undefined &&
|
|
292
|
+
JSON.stringify(existing.value) === JSON.stringify(input.value);
|
|
293
|
+
if (sameValue) {
|
|
294
|
+
const added = this.addEvidenceTx(existing.memory_id, { ...input.evidence, polarity: "support", summary: evidenceSummaryFor(input, input.evidence.summary) }, now, true);
|
|
295
|
+
const updated = this.getMemory(existing.memory_id);
|
|
296
|
+
this.maybeAutoActivate(updated, now);
|
|
297
|
+
return { kind: "merged", memory: this.getMemory(existing.memory_id), evidence_added: added };
|
|
298
|
+
}
|
|
299
|
+
// Value conflict. A recent explicit user statement supersedes; anything
|
|
300
|
+
// weaker only appends contradict evidence — never a silent overwrite.
|
|
301
|
+
if (input.explicit_user_statement) {
|
|
302
|
+
this.db
|
|
303
|
+
.prepare("UPDATE memory_items SET status = 'superseded', updated_at = ? WHERE memory_id = ?")
|
|
304
|
+
.run(now, existing.memory_id);
|
|
305
|
+
this.appendEvent(existing.memory_id, "memory.superseded", input.actor, "replaced by a newer explicit statement", { before: auditSnapshot(existing), after: { status: "superseded" } }, now);
|
|
306
|
+
const humanConfirm = requiresHumanConfirm(input);
|
|
307
|
+
const item = this.insertItem(existing.principal_id, input, scope, humanConfirm ? "candidate" : "active", humanConfirm ? (input.confidence ?? DEFAULT_CONFIDENCE[input.source_kind]) : 1.0, humanConfirm ? undefined : now, now);
|
|
308
|
+
this.addEvidenceTx(item.memory_id, { ...input.evidence, polarity: "support", summary: evidenceSummaryFor(input, input.evidence.summary) }, now, true);
|
|
309
|
+
this.appendEvent(item.memory_id, humanConfirm ? "memory.proposed" : "memory.confirmed", input.actor, undefined, {
|
|
310
|
+
after: auditSnapshot({ ...item, evidence_count: 1 }),
|
|
311
|
+
}, now);
|
|
312
|
+
return { kind: humanConfirm ? "candidate" : "active", memory: { ...item, evidence_count: 1 } };
|
|
313
|
+
}
|
|
314
|
+
const added = this.addEvidenceTx(existing.memory_id, { ...input.evidence, polarity: "contradict", summary: evidenceSummaryFor(input, input.evidence.summary) }, now, false);
|
|
315
|
+
if (added) {
|
|
316
|
+
this.appendEvent(existing.memory_id, "memory.contradicted", input.actor, evidenceSummaryFor(input, input.evidence.summary), { before: auditSnapshot(existing) }, now);
|
|
317
|
+
}
|
|
318
|
+
return {
|
|
319
|
+
kind: "conflict",
|
|
320
|
+
existing: this.getMemory(existing.memory_id),
|
|
321
|
+
evidence_added: added,
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
insertItem(principalId, input, scope, status, confidence, confirmedAt, now) {
|
|
325
|
+
const memoryId = `mem_${uuidv7()}`;
|
|
326
|
+
let valueJson = null;
|
|
327
|
+
let vaultRef = null;
|
|
328
|
+
if (input.restricted !== undefined) {
|
|
329
|
+
vaultRef = this.sealVault(principalId, input.restricted.kind, input.restricted.plaintext, now);
|
|
330
|
+
}
|
|
331
|
+
else {
|
|
332
|
+
valueJson = JSON.stringify(input.value ?? null);
|
|
333
|
+
}
|
|
334
|
+
this.db
|
|
335
|
+
.prepare(`INSERT INTO memory_items
|
|
336
|
+
(memory_id, principal_id, namespace, key, value_json, vault_ref, scope_json,
|
|
337
|
+
source_kind, confidence, sensitivity, status, confirmed_at, valid_from, expires_at,
|
|
338
|
+
last_observed_at, evidence_count, version, created_at, updated_at)
|
|
339
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, 1, ?, ?)`)
|
|
340
|
+
.run(memoryId, principalId, input.namespace, input.key, valueJson, vaultRef, JSON.stringify(scope), input.source_kind, confidence, input.sensitivity, status, confirmedAt ?? null, now, input.expires_at ?? null, now, now, now);
|
|
341
|
+
return this.getMemory(memoryId);
|
|
342
|
+
}
|
|
343
|
+
sealVault(principalId, kind, plaintext, now) {
|
|
344
|
+
const fingerprint = this.vault.fingerprint(kind, plaintext);
|
|
345
|
+
const existing = this.db
|
|
346
|
+
.prepare("SELECT vault_ref FROM private_vault WHERE principal_id = ? AND kind = ? AND value_fingerprint = ?")
|
|
347
|
+
.get(principalId, kind, fingerprint);
|
|
348
|
+
if (existing !== undefined)
|
|
349
|
+
return existing.vault_ref;
|
|
350
|
+
const sealed = this.vault.seal(kind, plaintext);
|
|
351
|
+
const ref = `vr_${uuidv7()}`;
|
|
352
|
+
this.db
|
|
353
|
+
.prepare(`INSERT INTO private_vault
|
|
354
|
+
(vault_ref, principal_id, kind, ciphertext, nonce, key_version, value_fingerprint,
|
|
355
|
+
retention_json, created_at, updated_at)
|
|
356
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, '{}', ?, ?)`)
|
|
357
|
+
.run(ref, principalId, kind, sealed.ciphertext, sealed.nonce, sealed.key_version, sealed.value_fingerprint, now, now);
|
|
358
|
+
return ref;
|
|
359
|
+
}
|
|
360
|
+
// ---- evidence -----------------------------------------------------------
|
|
361
|
+
/**
|
|
362
|
+
* Add evidence. Dedup (design §9.3): a repeat from the same source_ref
|
|
363
|
+
* never inflates evidence_count; only supporting, deduplicated evidence
|
|
364
|
+
* counts. Returns true when a new evidence row was inserted.
|
|
365
|
+
*/
|
|
366
|
+
addEvidenceTx(memoryId, input, now, counts) {
|
|
367
|
+
const dup = this.db
|
|
368
|
+
.prepare("SELECT 1 AS x FROM memory_evidence WHERE memory_id = ? AND source_ref = ? LIMIT 1")
|
|
369
|
+
.get(memoryId, input.source_ref);
|
|
370
|
+
if (dup !== undefined)
|
|
371
|
+
return false;
|
|
372
|
+
const evidenceId = `ev_${uuidv7()}`;
|
|
373
|
+
this.db
|
|
374
|
+
.prepare(`INSERT INTO memory_evidence
|
|
375
|
+
(evidence_id, memory_id, source_type, source_ref, polarity, weight, summary, observed_at, created_at)
|
|
376
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
377
|
+
.run(evidenceId, memoryId, input.source_type, input.source_ref, input.polarity, Math.min(1, Math.max(0, input.weight ?? 1)), input.summary, input.observed_at ?? now, now);
|
|
378
|
+
if (counts && input.polarity === "support") {
|
|
379
|
+
this.db
|
|
380
|
+
.prepare(`UPDATE memory_items
|
|
381
|
+
SET evidence_count = (SELECT COUNT(DISTINCT source_ref) FROM memory_evidence
|
|
382
|
+
WHERE memory_id = ? AND polarity = 'support'),
|
|
383
|
+
last_observed_at = ?, updated_at = ?
|
|
384
|
+
WHERE memory_id = ?`)
|
|
385
|
+
.run(memoryId, now, now, memoryId);
|
|
386
|
+
}
|
|
387
|
+
return true;
|
|
388
|
+
}
|
|
389
|
+
/** >= 3 deduplicated signals activate a soft preference (design §10.1). */
|
|
390
|
+
maybeAutoActivate(item, now) {
|
|
391
|
+
if (item.status !== "candidate")
|
|
392
|
+
return;
|
|
393
|
+
if (!SOFT_ACTIVATABLE.has(item.namespace))
|
|
394
|
+
return;
|
|
395
|
+
if (item.source_kind !== "observed" && item.source_kind !== "inferred")
|
|
396
|
+
return;
|
|
397
|
+
if (item.sensitivity === "restricted")
|
|
398
|
+
return;
|
|
399
|
+
if (item.evidence_count < AUTO_ACTIVATE_EVIDENCE)
|
|
400
|
+
return;
|
|
401
|
+
const confidence = Math.min(0.9, Math.max(item.confidence, 0.5 + 0.1 * item.evidence_count));
|
|
402
|
+
this.db
|
|
403
|
+
.prepare("UPDATE memory_items SET status = 'active', confidence = ?, updated_at = ? WHERE memory_id = ?")
|
|
404
|
+
.run(confidence, now, item.memory_id);
|
|
405
|
+
this.appendEvent(item.memory_id, "memory.activated", "system", "evidence threshold reached", {
|
|
406
|
+
before: auditSnapshot(item),
|
|
407
|
+
after: { status: "active", confidence },
|
|
408
|
+
}, now);
|
|
409
|
+
}
|
|
410
|
+
/** Public evidence hook (task feedback, selections, rejections). */
|
|
411
|
+
addEvidence(memoryId, input) {
|
|
412
|
+
const now = this.now();
|
|
413
|
+
this.db.exec("BEGIN");
|
|
414
|
+
try {
|
|
415
|
+
const added = this.addEvidenceTx(memoryId, { ...input, polarity: input.polarity ?? "support" }, now, true);
|
|
416
|
+
if (added) {
|
|
417
|
+
const item = this.getMemory(memoryId);
|
|
418
|
+
if (item !== undefined)
|
|
419
|
+
this.maybeAutoActivate(item, now);
|
|
420
|
+
}
|
|
421
|
+
this.db.exec("COMMIT");
|
|
422
|
+
return added;
|
|
423
|
+
}
|
|
424
|
+
catch (err) {
|
|
425
|
+
this.db.exec("ROLLBACK");
|
|
426
|
+
throw err;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
// ---- user governance ----------------------------------------------------
|
|
430
|
+
/** User confirms a candidate (design: Restricted candidates become valid only here). */
|
|
431
|
+
confirmMemory(memoryId, actor) {
|
|
432
|
+
const now = this.now();
|
|
433
|
+
const item = this.requireMemory(memoryId);
|
|
434
|
+
if (item.status !== "candidate" && item.status !== "needs_review") {
|
|
435
|
+
throw new MemoryError("conflict", `memory ${memoryId} is ${item.status}, not confirmable`);
|
|
436
|
+
}
|
|
437
|
+
const confidence = item.source_kind === "explicit" ? 1.0 : Math.max(item.confidence, 0.9);
|
|
438
|
+
this.db.exec("BEGIN");
|
|
439
|
+
try {
|
|
440
|
+
this.db
|
|
441
|
+
.prepare(`UPDATE memory_items
|
|
442
|
+
SET status = 'active', confirmed_at = ?, confidence = ?, source_kind = 'explicit', updated_at = ?
|
|
443
|
+
WHERE memory_id = ?`)
|
|
444
|
+
.run(now, confidence, now, memoryId);
|
|
445
|
+
this.appendEvent(memoryId, "memory.confirmed", actor, undefined, {
|
|
446
|
+
before: auditSnapshot(item),
|
|
447
|
+
after: { status: "active", confidence },
|
|
448
|
+
}, now);
|
|
449
|
+
this.db.exec("COMMIT");
|
|
450
|
+
}
|
|
451
|
+
catch (err) {
|
|
452
|
+
this.db.exec("ROLLBACK");
|
|
453
|
+
throw err;
|
|
454
|
+
}
|
|
455
|
+
return this.getMemory(memoryId);
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* User correction (design §6.4 /correct): updates in place with a version
|
|
459
|
+
* bump and a before/after audit event. A correction IS an explicit user
|
|
460
|
+
* statement: source becomes explicit, confidence 1.0, confirmed.
|
|
461
|
+
* Restricted items keep their Vault value unless a new plaintext is given;
|
|
462
|
+
* sensitivity downgrades from restricted are refused.
|
|
463
|
+
*/
|
|
464
|
+
correctMemory(memoryId, patch, actor, reason) {
|
|
465
|
+
const item = this.requireMemory(memoryId);
|
|
466
|
+
if (item.status === "deleted" || item.status === "superseded" || item.status === "expired") {
|
|
467
|
+
throw new MemoryError("conflict", `memory ${memoryId} is ${item.status}; cannot correct`);
|
|
468
|
+
}
|
|
469
|
+
const now = this.now();
|
|
470
|
+
this.db.exec("BEGIN");
|
|
471
|
+
try {
|
|
472
|
+
let valueJson;
|
|
473
|
+
let vaultRef;
|
|
474
|
+
if (patch.restricted !== undefined) {
|
|
475
|
+
if (item.sensitivity !== "restricted") {
|
|
476
|
+
throw new MemoryError("validation", "cannot move a non-restricted memory into the Vault; forget it and remember again");
|
|
477
|
+
}
|
|
478
|
+
if (!this.vault.available) {
|
|
479
|
+
throw new MemoryError("vault_unavailable", "no data key configured (KIWI_DATA_KEY)");
|
|
480
|
+
}
|
|
481
|
+
vaultRef = this.sealVault(item.principal_id, patch.restricted.kind, patch.restricted.plaintext, now);
|
|
482
|
+
valueJson = null;
|
|
483
|
+
}
|
|
484
|
+
else if (patch.value !== undefined) {
|
|
485
|
+
if (item.sensitivity === "restricted") {
|
|
486
|
+
throw new MemoryError("validation", "cannot move a Restricted value out of the Vault; forget it and remember again");
|
|
487
|
+
}
|
|
488
|
+
assertJsonValue(patch.value, "value");
|
|
489
|
+
valueJson = JSON.stringify(patch.value);
|
|
490
|
+
vaultRef = null;
|
|
491
|
+
}
|
|
492
|
+
const scopeJson = patch.scope !== undefined ? JSON.stringify(parseMemoryScope(patch.scope)) : undefined;
|
|
493
|
+
this.db
|
|
494
|
+
.prepare(`UPDATE memory_items
|
|
495
|
+
SET value_json = COALESCE(?, value_json),
|
|
496
|
+
vault_ref = COALESCE(?, vault_ref),
|
|
497
|
+
scope_json = COALESCE(?, scope_json),
|
|
498
|
+
source_kind = 'explicit', confidence = 1.0, confirmed_at = ?,
|
|
499
|
+
status = CASE WHEN status = 'candidate' THEN 'active' ELSE status END,
|
|
500
|
+
version = version + 1, updated_at = ?
|
|
501
|
+
WHERE memory_id = ?`)
|
|
502
|
+
.run(valueJson === undefined ? null : valueJson, vaultRef === undefined ? null : vaultRef, scopeJson === undefined ? null : scopeJson, now, now, memoryId);
|
|
503
|
+
const updated = this.getMemory(memoryId);
|
|
504
|
+
this.appendEvent(memoryId, "memory.corrected", actor, reason, {
|
|
505
|
+
before: auditSnapshot(item),
|
|
506
|
+
after: auditSnapshot(updated),
|
|
507
|
+
}, now);
|
|
508
|
+
this.db.exec("COMMIT");
|
|
509
|
+
return updated;
|
|
510
|
+
}
|
|
511
|
+
catch (err) {
|
|
512
|
+
this.db.exec("ROLLBACK");
|
|
513
|
+
if (err instanceof MemoryError || err instanceof VaultKeyError)
|
|
514
|
+
throw err;
|
|
515
|
+
throw new MemoryError("validation", err instanceof Error ? err.message : String(err));
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Forget (tombstone + audit; design §9.2). The Vault ciphertext of a
|
|
520
|
+
* Restricted memory is hard-deleted; retrieval never returns the item.
|
|
521
|
+
*/
|
|
522
|
+
forgetMemory(memoryId, actor, reason) {
|
|
523
|
+
const item = this.requireMemory(memoryId);
|
|
524
|
+
if (item.status === "deleted")
|
|
525
|
+
return item;
|
|
526
|
+
const now = this.now();
|
|
527
|
+
this.db.exec("BEGIN");
|
|
528
|
+
try {
|
|
529
|
+
this.db
|
|
530
|
+
.prepare("UPDATE memory_items SET status = 'deleted', updated_at = ? WHERE memory_id = ?")
|
|
531
|
+
.run(now, memoryId);
|
|
532
|
+
// Vault rows are fingerprint-deduped and can be shared by several memory
|
|
533
|
+
// items (design §9.5). Only erase the ciphertext when no OTHER live item
|
|
534
|
+
// still references it — otherwise /forget of one would silently destroy
|
|
535
|
+
// the other's private value.
|
|
536
|
+
if (item.vault_ref !== undefined) {
|
|
537
|
+
const stillReferenced = this.db
|
|
538
|
+
.prepare("SELECT COUNT(*) AS c FROM memory_items WHERE vault_ref = ? AND memory_id != ? AND status != 'deleted'")
|
|
539
|
+
.get(item.vault_ref, memoryId);
|
|
540
|
+
if (stillReferenced.c === 0) {
|
|
541
|
+
this.db.prepare("DELETE FROM private_vault WHERE vault_ref = ?").run(item.vault_ref);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
this.appendEvent(memoryId, "memory.forgotten", actor, reason, {
|
|
545
|
+
before: auditSnapshot(item),
|
|
546
|
+
after: { status: "deleted", vault: item.vault_ref !== undefined ? "erased" : undefined },
|
|
547
|
+
}, now);
|
|
548
|
+
this.db.exec("COMMIT");
|
|
549
|
+
}
|
|
550
|
+
catch (err) {
|
|
551
|
+
this.db.exec("ROLLBACK");
|
|
552
|
+
throw err;
|
|
553
|
+
}
|
|
554
|
+
return this.getMemory(memoryId);
|
|
555
|
+
}
|
|
556
|
+
/** Expire due items (task_context after its task, dated memories at expires_at). */
|
|
557
|
+
expireDue() {
|
|
558
|
+
const now = this.now();
|
|
559
|
+
const due = this.db
|
|
560
|
+
.prepare(`SELECT memory_id FROM memory_items
|
|
561
|
+
WHERE status IN ('candidate','active','needs_review') AND expires_at IS NOT NULL AND expires_at < ?`)
|
|
562
|
+
.all(now);
|
|
563
|
+
this.db.exec("BEGIN");
|
|
564
|
+
try {
|
|
565
|
+
for (const { memory_id: dueId } of due) {
|
|
566
|
+
const item = this.getMemory(dueId);
|
|
567
|
+
this.db
|
|
568
|
+
.prepare("UPDATE memory_items SET status = 'expired', updated_at = ? WHERE memory_id = ?")
|
|
569
|
+
.run(now, dueId);
|
|
570
|
+
this.appendEvent(dueId, "memory.expired", "system", `expired at ${item.expires_at ?? ""}`, {
|
|
571
|
+
before: auditSnapshot(item),
|
|
572
|
+
after: { status: "expired" },
|
|
573
|
+
}, now);
|
|
574
|
+
}
|
|
575
|
+
this.db.exec("COMMIT");
|
|
576
|
+
}
|
|
577
|
+
catch (err) {
|
|
578
|
+
this.db.exec("ROLLBACK");
|
|
579
|
+
throw err;
|
|
580
|
+
}
|
|
581
|
+
return due.length;
|
|
582
|
+
}
|
|
583
|
+
// ---- retrieval ----------------------------------------------------------
|
|
584
|
+
retrieve(query) {
|
|
585
|
+
if (!isRetrievalPurpose(query.purpose)) {
|
|
586
|
+
throw new MemoryError("validation", `unknown retrieval purpose: ${String(query.purpose)}`);
|
|
587
|
+
}
|
|
588
|
+
const principal = this.requirePrincipal();
|
|
589
|
+
this.expireDue();
|
|
590
|
+
const now = this.now();
|
|
591
|
+
const limit = Math.min(MAX_LIMIT, Math.max(1, query.limit ?? 8));
|
|
592
|
+
const rows = this.db
|
|
593
|
+
.prepare(`SELECT * FROM memory_items
|
|
594
|
+
WHERE principal_id = ? AND status IN ('active','needs_review')`)
|
|
595
|
+
.all(principal.principal_id);
|
|
596
|
+
const queryTokens = tokenize(query.text);
|
|
597
|
+
const scored = [];
|
|
598
|
+
for (const row of rows) {
|
|
599
|
+
const item = this.rowToItem(row);
|
|
600
|
+
if (query.namespaces !== undefined && !query.namespaces.includes(item.namespace))
|
|
601
|
+
continue;
|
|
602
|
+
if (item.namespace === "task_context") {
|
|
603
|
+
if (query.task_id === undefined || item.scope.task_id !== query.task_id)
|
|
604
|
+
continue;
|
|
605
|
+
}
|
|
606
|
+
const scopeMatch = scopeScore(item.scope, query.scopes);
|
|
607
|
+
if (scopeMatch === 0)
|
|
608
|
+
continue;
|
|
609
|
+
const relevance = relevanceScore(item, queryTokens);
|
|
610
|
+
const freshness = freshnessScore(item, now);
|
|
611
|
+
const penalty = item.status === "needs_review" ? 0.5 : 1;
|
|
612
|
+
const score = relevance *
|
|
613
|
+
scopeMatch *
|
|
614
|
+
item.confidence *
|
|
615
|
+
freshness *
|
|
616
|
+
SOURCE_WEIGHT[item.source_kind] *
|
|
617
|
+
penalty;
|
|
618
|
+
scored.push({
|
|
619
|
+
memory_id: item.memory_id,
|
|
620
|
+
namespace: item.namespace,
|
|
621
|
+
key: item.key,
|
|
622
|
+
...(item.vault_ref === undefined ? { value: item.value } : {}),
|
|
623
|
+
scope: item.scope,
|
|
624
|
+
source_kind: item.source_kind,
|
|
625
|
+
confidence: item.confidence,
|
|
626
|
+
sensitivity: item.sensitivity,
|
|
627
|
+
status: item.status,
|
|
628
|
+
redaction_level: redactionLevel(item.sensitivity),
|
|
629
|
+
score,
|
|
630
|
+
...(item.last_observed_at !== undefined
|
|
631
|
+
? { last_observed_at: item.last_observed_at }
|
|
632
|
+
: {}),
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
scored.sort((a, b) => b.score - a.score || a.memory_id.localeCompare(b.memory_id));
|
|
636
|
+
const picked = scored.slice(0, limit);
|
|
637
|
+
for (const item of picked) {
|
|
638
|
+
this.db
|
|
639
|
+
.prepare(`INSERT INTO memory_retrieval_log
|
|
640
|
+
(retrieval_id, task_id, session_id, memory_id, purpose, redaction_level, created_at)
|
|
641
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`)
|
|
642
|
+
.run(`ret_${uuidv7()}`, query.task_id ?? null, query.session_id, item.memory_id, query.purpose, item.redaction_level, now);
|
|
643
|
+
}
|
|
644
|
+
return picked;
|
|
645
|
+
}
|
|
646
|
+
/** Data behind /why: the most recent retrieval batch for a session. */
|
|
647
|
+
explainLastRetrieval(sessionId) {
|
|
648
|
+
const last = this.db
|
|
649
|
+
.prepare("SELECT created_at FROM memory_retrieval_log WHERE session_id = ? ORDER BY created_at DESC LIMIT 1")
|
|
650
|
+
.get(sessionId);
|
|
651
|
+
if (last === undefined)
|
|
652
|
+
return { entries: [] };
|
|
653
|
+
const rows = this.db
|
|
654
|
+
.prepare(`SELECT l.*, i.key AS key, i.namespace AS namespace, i.confidence AS confidence
|
|
655
|
+
FROM memory_retrieval_log l JOIN memory_items i ON i.memory_id = l.memory_id
|
|
656
|
+
WHERE l.session_id = ? AND l.created_at = ?
|
|
657
|
+
ORDER BY l.memory_id`)
|
|
658
|
+
.all(sessionId, last.created_at);
|
|
659
|
+
return {
|
|
660
|
+
entries: rows.map((r) => ({
|
|
661
|
+
retrieval_id: r.retrieval_id,
|
|
662
|
+
task_id: r.task_id ?? undefined,
|
|
663
|
+
session_id: r.session_id,
|
|
664
|
+
memory_id: r.memory_id,
|
|
665
|
+
purpose: r.purpose,
|
|
666
|
+
redaction_level: r.redaction_level,
|
|
667
|
+
created_at: r.created_at,
|
|
668
|
+
key: r.key,
|
|
669
|
+
namespace: r.namespace,
|
|
670
|
+
confidence: r.confidence,
|
|
671
|
+
})),
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
retrievalLog(sessionId) {
|
|
675
|
+
const rows = this.db
|
|
676
|
+
.prepare("SELECT * FROM memory_retrieval_log WHERE session_id = ? ORDER BY created_at, memory_id")
|
|
677
|
+
.all(sessionId);
|
|
678
|
+
return rows.map((r) => ({
|
|
679
|
+
retrieval_id: r.retrieval_id,
|
|
680
|
+
task_id: r.task_id ?? undefined,
|
|
681
|
+
session_id: r.session_id,
|
|
682
|
+
memory_id: r.memory_id,
|
|
683
|
+
purpose: r.purpose,
|
|
684
|
+
redaction_level: r.redaction_level,
|
|
685
|
+
created_at: r.created_at,
|
|
686
|
+
}));
|
|
687
|
+
}
|
|
688
|
+
// ---- reads / listings ---------------------------------------------------
|
|
689
|
+
getMemory(memoryId) {
|
|
690
|
+
const row = this.db
|
|
691
|
+
.prepare("SELECT * FROM memory_items WHERE memory_id = ?")
|
|
692
|
+
.get(memoryId);
|
|
693
|
+
return row === undefined ? undefined : this.rowToItem(row);
|
|
694
|
+
}
|
|
695
|
+
/** /memory overview. Restricted items are listed without any value. */
|
|
696
|
+
listMemories(filter) {
|
|
697
|
+
const principal = this.requirePrincipal();
|
|
698
|
+
const statuses = filter.statuses ?? ["candidate", "active", "needs_review"];
|
|
699
|
+
const rows = this.db
|
|
700
|
+
.prepare(`SELECT * FROM memory_items
|
|
701
|
+
WHERE principal_id = ?
|
|
702
|
+
AND (${statuses.map(() => "status = ?").join(" OR ")})
|
|
703
|
+
AND (? IS NULL OR namespace = ?)
|
|
704
|
+
AND (? IS NULL OR sensitivity = ?)
|
|
705
|
+
ORDER BY namespace, key`)
|
|
706
|
+
.all(principal.principal_id, ...statuses, filter.namespace ?? null, filter.namespace ?? null, filter.sensitivity ?? null, filter.sensitivity ?? null);
|
|
707
|
+
return rows.map((r) => this.rowToItem(r));
|
|
708
|
+
}
|
|
709
|
+
memoryEvents(memoryId) {
|
|
710
|
+
const rows = this.db
|
|
711
|
+
.prepare("SELECT * FROM memory_events WHERE memory_id = ? ORDER BY created_at, event_id")
|
|
712
|
+
.all(memoryId);
|
|
713
|
+
return rows.map((r) => ({
|
|
714
|
+
event_id: r.event_id,
|
|
715
|
+
memory_id: r.memory_id,
|
|
716
|
+
type: r.type,
|
|
717
|
+
actor: r.actor,
|
|
718
|
+
reason: r.reason ?? undefined,
|
|
719
|
+
before_json: r.before_json === null ? undefined : JSON.parse(r.before_json),
|
|
720
|
+
after_json: r.after_json === null ? undefined : JSON.parse(r.after_json),
|
|
721
|
+
created_at: r.created_at,
|
|
722
|
+
}));
|
|
723
|
+
}
|
|
724
|
+
/** Vault metadata for /memory private — never ciphertext, never plaintext. */
|
|
725
|
+
vaultEntries() {
|
|
726
|
+
const principal = this.requirePrincipal();
|
|
727
|
+
const rows = this.db
|
|
728
|
+
.prepare("SELECT vault_ref, kind, created_at FROM private_vault WHERE principal_id = ? ORDER BY created_at")
|
|
729
|
+
.all(principal.principal_id);
|
|
730
|
+
return rows.map((r) => ({
|
|
731
|
+
vault_ref: r.vault_ref,
|
|
732
|
+
kind: r.kind,
|
|
733
|
+
created_at: r.created_at,
|
|
734
|
+
}));
|
|
735
|
+
}
|
|
736
|
+
/** Open a Vault value (owner-side use only; never exposed to the model). */
|
|
737
|
+
openVaultValue(vaultRef) {
|
|
738
|
+
const principal = this.requirePrincipal();
|
|
739
|
+
const row = this.db
|
|
740
|
+
.prepare("SELECT * FROM private_vault WHERE vault_ref = ? AND principal_id = ?")
|
|
741
|
+
.get(vaultRef, principal.principal_id);
|
|
742
|
+
if (row === undefined) {
|
|
743
|
+
throw new MemoryError("not_found", `no vault entry ${vaultRef}`);
|
|
744
|
+
}
|
|
745
|
+
return this.vault.open(row.key_version, row.nonce, row.ciphertext);
|
|
746
|
+
}
|
|
747
|
+
// ---- internals ----------------------------------------------------------
|
|
748
|
+
principalId;
|
|
749
|
+
/** Bind the store to one principal (set by the kernel after ensurePrincipal). */
|
|
750
|
+
bindPrincipal(principalId) {
|
|
751
|
+
this.principalId = principalId;
|
|
752
|
+
}
|
|
753
|
+
requirePrincipal() {
|
|
754
|
+
if (this.principalId === undefined) {
|
|
755
|
+
throw new MemoryError("validation", "MemoryStore is not bound to a principal");
|
|
756
|
+
}
|
|
757
|
+
const principal = this.getPrincipal(this.principalId);
|
|
758
|
+
if (principal === undefined) {
|
|
759
|
+
throw new MemoryError("not_found", `principal ${this.principalId} does not exist`);
|
|
760
|
+
}
|
|
761
|
+
return principal;
|
|
762
|
+
}
|
|
763
|
+
requireMemory(memoryId) {
|
|
764
|
+
const item = this.getMemory(memoryId);
|
|
765
|
+
if (item === undefined) {
|
|
766
|
+
throw new MemoryError("not_found", `no memory ${memoryId}`);
|
|
767
|
+
}
|
|
768
|
+
return item;
|
|
769
|
+
}
|
|
770
|
+
findLiveByKey(principalId, namespace, key, scope) {
|
|
771
|
+
const row = this.db
|
|
772
|
+
.prepare(`SELECT * FROM memory_items
|
|
773
|
+
WHERE principal_id = ? AND namespace = ? AND key = ? AND scope_json = ?
|
|
774
|
+
AND status IN ('candidate','active','needs_review')
|
|
775
|
+
ORDER BY created_at DESC LIMIT 1`)
|
|
776
|
+
.get(principalId, namespace, key, JSON.stringify(scope));
|
|
777
|
+
return row === undefined ? undefined : this.rowToItem(row);
|
|
778
|
+
}
|
|
779
|
+
rowToItem(row) {
|
|
780
|
+
const item = {
|
|
781
|
+
memory_id: row.memory_id,
|
|
782
|
+
principal_id: row.principal_id,
|
|
783
|
+
namespace: row.namespace,
|
|
784
|
+
key: row.key,
|
|
785
|
+
scope: JSON.parse(row.scope_json),
|
|
786
|
+
source_kind: row.source_kind,
|
|
787
|
+
confidence: row.confidence,
|
|
788
|
+
sensitivity: row.sensitivity,
|
|
789
|
+
status: row.status,
|
|
790
|
+
evidence_count: row.evidence_count,
|
|
791
|
+
version: row.version,
|
|
792
|
+
created_at: row.created_at,
|
|
793
|
+
updated_at: row.updated_at,
|
|
794
|
+
};
|
|
795
|
+
if (row.value_json !== null)
|
|
796
|
+
item.value = JSON.parse(row.value_json);
|
|
797
|
+
if (row.vault_ref !== null)
|
|
798
|
+
item.vault_ref = row.vault_ref;
|
|
799
|
+
const confirmed = optText(row.confirmed_at);
|
|
800
|
+
if (confirmed !== undefined)
|
|
801
|
+
item.confirmed_at = confirmed;
|
|
802
|
+
const validFrom = optText(row.valid_from);
|
|
803
|
+
if (validFrom !== undefined)
|
|
804
|
+
item.valid_from = validFrom;
|
|
805
|
+
const expires = optText(row.expires_at);
|
|
806
|
+
if (expires !== undefined)
|
|
807
|
+
item.expires_at = expires;
|
|
808
|
+
const observed = optText(row.last_observed_at);
|
|
809
|
+
if (observed !== undefined)
|
|
810
|
+
item.last_observed_at = observed;
|
|
811
|
+
return item;
|
|
812
|
+
}
|
|
813
|
+
appendEvent(memoryId, type, actor, reason, snapshots, now) {
|
|
814
|
+
for (const [label, snap] of [
|
|
815
|
+
["before", snapshots.before],
|
|
816
|
+
["after", snapshots.after],
|
|
817
|
+
]) {
|
|
818
|
+
if (snap !== undefined)
|
|
819
|
+
assertJsonValue(snap, `memory_event.${label}`);
|
|
820
|
+
}
|
|
821
|
+
this.db
|
|
822
|
+
.prepare(`INSERT INTO memory_events
|
|
823
|
+
(event_id, memory_id, type, actor, reason, before_json, after_json, created_at)
|
|
824
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
825
|
+
.run(`mev_${uuidv7()}`, memoryId, type, actor, reason ?? null, snapshots.before === undefined ? null : JSON.stringify(snapshots.before), snapshots.after === undefined ? null : JSON.stringify(snapshots.after), now);
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
function redactionLevel(sensitivity) {
|
|
829
|
+
return sensitivity === "restricted" ? "metadata_only" : sensitivity === "private" ? "coarse" : "full";
|
|
830
|
+
}
|
|
831
|
+
/** Deterministic tokenizer for relevance matching (CJK bigrams + word tokens). */
|
|
832
|
+
function tokenize(text) {
|
|
833
|
+
if (text === undefined || text.trim() === "")
|
|
834
|
+
return [];
|
|
835
|
+
const lower = text.toLowerCase();
|
|
836
|
+
const words = lower.match(/[a-z0-9_]{2,}/g) ?? [];
|
|
837
|
+
const cjk = lower.match(/[一-鿿]/g) ?? [];
|
|
838
|
+
const bigrams = [];
|
|
839
|
+
for (let i = 0; i + 1 < cjk.length; i++)
|
|
840
|
+
bigrams.push(`${cjk[i]}${cjk[i + 1]}`);
|
|
841
|
+
return [...new Set([...words, ...bigrams])];
|
|
842
|
+
}
|
|
843
|
+
function relevanceScore(item, queryTokens) {
|
|
844
|
+
if (queryTokens.length === 0)
|
|
845
|
+
return 1;
|
|
846
|
+
const haystack = `${item.key} ${JSON.stringify(item.value ?? "")}`.toLowerCase();
|
|
847
|
+
let hits = 0;
|
|
848
|
+
for (const token of queryTokens) {
|
|
849
|
+
if (haystack.includes(token))
|
|
850
|
+
hits += 1;
|
|
851
|
+
}
|
|
852
|
+
return Math.min(1, Math.max(0.1, hits / queryTokens.length + (hits > 0 ? 0.2 : 0)));
|
|
853
|
+
}
|
|
854
|
+
function scopeScore(scope, queryScopes) {
|
|
855
|
+
const entries = Object.entries(scope).filter(([, v]) => v !== undefined);
|
|
856
|
+
if (entries.length === 0)
|
|
857
|
+
return 1.0; // global memory
|
|
858
|
+
if (queryScopes === undefined || queryScopes.length === 0)
|
|
859
|
+
return 0.6; // scoped memory, global query
|
|
860
|
+
let matched = false;
|
|
861
|
+
for (const [dimension, value] of entries) {
|
|
862
|
+
for (const qs of queryScopes) {
|
|
863
|
+
const qv = qs[dimension];
|
|
864
|
+
if (qv === undefined)
|
|
865
|
+
continue;
|
|
866
|
+
if (qv === value)
|
|
867
|
+
matched = true;
|
|
868
|
+
else
|
|
869
|
+
return 0.4; // explicit contradiction on a shared dimension
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
return matched ? 1.2 : 0.6;
|
|
873
|
+
}
|
|
874
|
+
function freshnessScore(item, now) {
|
|
875
|
+
if (item.last_observed_at === undefined)
|
|
876
|
+
return 1;
|
|
877
|
+
const ageMs = Date.parse(now) - Date.parse(item.last_observed_at);
|
|
878
|
+
const ageDays = Math.max(0, ageMs / 86_400_000);
|
|
879
|
+
return 0.5 + 0.5 * Math.exp(-ageDays / 90);
|
|
880
|
+
}
|
|
881
|
+
//# sourceMappingURL=store.js.map
|