diff --git a/.changeset/allow-header-405.md b/.changeset/allow-header-405.md deleted file mode 100644 index bd0c54af..00000000 --- a/.changeset/allow-header-405.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/server": patch ---- - -405 responses now include `Allow: POST, OPTIONS`. diff --git a/.changeset/analytics-event-names.md b/.changeset/analytics-event-names.md deleted file mode 100644 index 52fa28da..00000000 --- a/.changeset/analytics-event-names.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@chatcops/core": minor -"@chatcops/server": minor ---- - -Analytics events are named `noun.verb` now: `conversation.started`, `message.sent`, `message.received` and `lead.captured`, also exported as `ANALYTICS_EVENTS`. The old `noun:verb` names keep working until 1.0. `track()` and `getEvents()` read them as the new ones, stats count events a store saved under either, and `eventCounts` has both keys, so the numbers carry on across the upgrade. Stats gain `leadsCaptured`. `leadsCapture`, the same number, is deprecated. A custom `EventSink` now receives the new names. Webhook event names don't change. diff --git a/.changeset/announce-streamed-replies.md b/.changeset/announce-streamed-replies.md deleted file mode 100644 index 75365f2d..00000000 --- a/.changeset/announce-streamed-replies.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/widget": patch ---- - -Announce completed assistant replies once for screen readers. diff --git a/.changeset/anthropic-sdk-1.md b/.changeset/anthropic-sdk-1.md deleted file mode 100644 index 93f8f1df..00000000 --- a/.changeset/anthropic-sdk-1.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/core": patch ---- - -The Claude provider now uses `@anthropic-ai/sdk` 1.x, which talks to Claude's API version 2026-10-21. That version removed `temperature`, so it's never sent to Claude: a configured `temperature` logs one warning and is left out. Claude 4.7 and later, including the default `claude-haiku-5-5`, already ignored it. On older Claude models a lowered `temperature` no longer has an effect; use `effort` instead. diff --git a/.changeset/arabic-widget-locale.md b/.changeset/arabic-widget-locale.md deleted file mode 100644 index a09b0105..00000000 --- a/.changeset/arabic-widget-locale.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/widget": patch ---- - -Add Arabic widget translations, loaded only for visitors using Arabic. diff --git a/.changeset/brave-oranges-refuse.md b/.changeset/brave-oranges-refuse.md deleted file mode 100644 index e7cdbf1d..00000000 --- a/.changeset/brave-oranges-refuse.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/widget": patch ---- - -Show unread reply count in the launcher badge and accessible name. diff --git a/.changeset/bright-questions-start.md b/.changeset/bright-questions-start.md deleted file mode 100644 index 5b43aaa5..00000000 --- a/.changeset/bright-questions-start.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/widget": minor ---- - -Add configurable suggested question buttons to new widget conversations. diff --git a/.changeset/bright-rerankers-smile.md b/.changeset/bright-rerankers-smile.md deleted file mode 100644 index ee6f0893..00000000 --- a/.changeset/bright-rerankers-smile.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/core": minor ---- - -Add a Cloudflare Workers AI reranker for knowledge retrieval. diff --git a/.changeset/bright-rerankers-sort.md b/.changeset/bright-rerankers-sort.md deleted file mode 100644 index a2ed984d..00000000 --- a/.changeset/bright-rerankers-sort.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/core": minor ---- - -Add `cohereReranker` for reranking retrieved chunks with Cohere's Rerank API. diff --git a/.changeset/chatcops-test.md b/.changeset/chatcops-test.md deleted file mode 100644 index 6050d868..00000000 --- a/.changeset/chatcops-test.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"@chatcops/cli": minor -"@chatcops/ingest": patch ---- - -`chatcops test` runs eval files against your bot: YAML conversations (`evals/**/*.chat.yaml`, or `.chat.ts`/`.chat.mjs` modules) with assertions on each reply. It uses the config's new `server` section and runs through the real request path with fresh in-memory storage, tool mocks, page context, locale, `repeat` and `passRate`. Options: `--filter` (name or `tag:x`), `--repeat`, `--concurrency`, `--reporter pretty|json` (repeatable) and `--json`. Exit 0 when all passed, 1 when some failed, 2 when it couldn't run. This first version has the `contains` assertion (and `not-contains`); more are coming. - -`ingest` and `search` now say what's missing from the config when they run, so a config with only `server` works for `chatcops test`. - -`globToRegExp` in `@chatcops/ingest`: `**/` now also matches no folder, so `docs/**/*.md` matches `docs/intro.md`. diff --git a/.changeset/chinese-widget-locale.md b/.changeset/chinese-widget-locale.md deleted file mode 100644 index 82f725f2..00000000 --- a/.changeset/chinese-widget-locale.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/widget": patch ---- - -Add Simplified Chinese widget translations, loaded only for visitors using Chinese. diff --git a/.changeset/citations.md b/.changeset/citations.md deleted file mode 100644 index 565bb39c..00000000 --- a/.changeset/citations.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@chatcops/core": minor -"@chatcops/server": minor ---- - -Answers now cite the pages they came from. Chunks from knowledge sources with `retrieve` are passed to the turn as `sources`, and each page the reply cites becomes a `source` part (once per page), streamed after the text and saved with the reply. Claude gets the chunks as `search_result` blocks and cites them natively; other providers get a numbered `` block and cite with `[n]`, and numbers that match no source are removed from the text. New in core: `sources` on `runTurn` and provider step params, `citations: 'native'` on providers, a `source` provider event, and `CitationParser`/`parseCitations`/`sourcePart`. diff --git a/.changeset/cjk-knowledge-sources.md b/.changeset/cjk-knowledge-sources.md deleted file mode 100644 index 8e089db6..00000000 --- a/.changeset/cjk-knowledge-sources.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/core": patch ---- - -Support Japanese and Chinese in TextKnowledgeSource and FAQKnowledgeSource using word segmentation. diff --git a/.changeset/cli.md b/.changeset/cli.md deleted file mode 100644 index 58c402ec..00000000 --- a/.changeset/cli.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"@chatcops/cli": minor -"@chatcops/ingest": minor ---- - -New package: the `chatcops` command. `chatcops ingest` builds or updates a knowledge index from `chatcops.config.ts` or `--source` (sitemaps, page URLs, folders), with `--dry-run`, `--max-pages`, `--concurrency`, `--prune`, `--force`, `--index` and `--json` (one JSON object per line). `chatcops search` shows what retrieval finds for a question. Both refuse an embedder other than the one the index was built with. Exit codes: 0 done, 1 finished with failed pages or discovery errors, 2 could not run. - -`ingest()` takes `maxPages`; a capped run never prunes. diff --git a/.changeset/cloudflare-example-origins.md b/.changeset/cloudflare-example-origins.md deleted file mode 100644 index ff9d8411..00000000 --- a/.changeset/cloudflare-example-origins.md +++ /dev/null @@ -1,4 +0,0 @@ ---- ---- - -The Cloudflare Worker example uses `allowedOrigins` instead of the deprecated `cors`. diff --git a/.changeset/cloudflare-vectorize.md b/.changeset/cloudflare-vectorize.md deleted file mode 100644 index d6ae4598..00000000 --- a/.changeset/cloudflare-vectorize.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/store-cloudflare": minor ---- - -Add optional Cloudflare Vectorize and D1 vector storage with semantic and keyword search. diff --git a/.changeset/dutch-widget-locale.md b/.changeset/dutch-widget-locale.md deleted file mode 100644 index 84b2e4fa..00000000 --- a/.changeset/dutch-widget-locale.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/widget": patch ---- - -Add Dutch widget translations, loaded only for visitors using Dutch. diff --git a/.changeset/eleven-locales-disclosure.md b/.changeset/eleven-locales-disclosure.md deleted file mode 100644 index fedb04e7..00000000 --- a/.changeset/eleven-locales-disclosure.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/widget": patch ---- - -Add source labels and AI disclosure translations to 11 widget locales. diff --git a/.changeset/embedder-http.md b/.changeset/embedder-http.md deleted file mode 100644 index 44d560b2..00000000 --- a/.changeset/embedder-http.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/core": patch ---- - -`openaiEmbedder` now keeps `batchSize` between 1 and 2048 (what OpenAI accepts), so a value of 0 no longer loops forever. The OpenAI, Voyage and Gemini embedders share one implementation of retries and batching, with no change in behavior. diff --git a/.changeset/eval-cassettes-gzip.md b/.changeset/eval-cassettes-gzip.md deleted file mode 100644 index a9cdffb7..00000000 --- a/.changeset/eval-cassettes-gzip.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/cli": patch ---- - -Eval recordings save response bodies over 4 kB gzipped in base64 (`encoding: 'gzip'`), so a streamed reply, which is one event per token, takes about a tenth of the space. Request bodies stay readable JSON, so a re-recording's diff still shows what changed. diff --git a/.changeset/eval-cassettes.md b/.changeset/eval-cassettes.md deleted file mode 100644 index 7bcfef00..00000000 --- a/.changeset/eval-cassettes.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/cli": minor ---- - -`chatcops test --record` saves every HTTP call the tests make (model, embeddings, tools that call APIs) to `__cassettes__/.jsonl`, and `--replay` answers them from there without the network. Replay is the default when `CI` is set; `--live` calls the APIs anyway. Calls are matched by a hash of their method, URL and body, so a changed prompt, model or tool list fails with where the request changed and a note to re-record, instead of passing on an old answer. Headers and key-like query parameters are never saved. diff --git a/.changeset/eval-judge.md b/.changeset/eval-judge.md deleted file mode 100644 index dbb980ac..00000000 --- a/.changeset/eval-judge.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@chatcops/cli": minor ---- - -`judge` assertions in `chatcops test`: a model grades the reply against a rubric from 0 to 1 and passes at `threshold` (default 0.7). The default judge is the cheap model of a provider other than the bot's; `--judge-model provider:model` or `judge` in the config picks another. Without a key for it the run refuses to start, and every run prints the judge it used. Judge calls are recorded and replayed with the rest. - -`prices` in the config (US dollars per million tokens, by model id) gives each turn and judge call a cost, and the run prints what it spent. `--max-cost ` stops starting turns once a run has spent that much; it needs prices for the models in use. Reporters get a run summary (mode, judge, cost) in `onEnd`. diff --git a/.changeset/eval-turn-errors.md b/.changeset/eval-turn-errors.md deleted file mode 100644 index db092e26..00000000 --- a/.changeset/eval-turn-errors.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/cli": patch ---- - -`chatcops test` no longer stops the whole run when something throws while a reply is read, such as a knowledge source that can't reach its index (or a replay that has no recording for an embedding call). That test fails with `internal_error` and the message, and the other tests still run. diff --git a/.changeset/export-config-types.md b/.changeset/export-config-types.md deleted file mode 100644 index 9972d0c1..00000000 --- a/.changeset/export-config-types.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@chatcops/widget": minor -"@chatcops/server": minor ---- - -The types that make up a config are now exported, so a site can name them: `ThemeConfig`, `ThemeMode`, `PreChatField`, `PreChatFormConfig`, `Persistence`, `MessageStatus` and `MessageErrorType` from `@chatcops/widget`, and `TurnstileConfig` from `@chatcops/server`. diff --git a/.changeset/focus-ring-controls.md b/.changeset/focus-ring-controls.md deleted file mode 100644 index fe64cd01..00000000 --- a/.changeset/focus-ring-controls.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@chatcops/widget': patch ---- - -Add --cc-focus-ring on :host for visible keyboard focus indicators across widget controls. diff --git a/.changeset/french-widget-locale.md b/.changeset/french-widget-locale.md deleted file mode 100644 index ea0a1b5b..00000000 --- a/.changeset/french-widget-locale.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/widget": patch ---- - -Add French widget translations, loaded only for visitors using French. diff --git a/.changeset/gemini-embedder.md b/.changeset/gemini-embedder.md deleted file mode 100644 index 93d6817b..00000000 --- a/.changeset/gemini-embedder.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/core": minor ---- - -Add `geminiEmbedder` for embeddings via Google's Gemini batchEmbedContents API. diff --git a/.changeset/german-widget-locale.md b/.changeset/german-widget-locale.md deleted file mode 100644 index b6b0c0c1..00000000 --- a/.changeset/german-widget-locale.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/widget": patch ---- - -Add German widget translations, loaded only for visitors using German. diff --git a/.changeset/hebrew-widget-locale.md b/.changeset/hebrew-widget-locale.md deleted file mode 100644 index 44f1eec9..00000000 --- a/.changeset/hebrew-widget-locale.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/widget": patch ---- - -Add Hebrew widget translations, loaded only for visitors using Hebrew. diff --git a/.changeset/hi-widget-locale.md b/.changeset/hi-widget-locale.md deleted file mode 100644 index 714e8868..00000000 --- a/.changeset/hi-widget-locale.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/widget": patch ---- - -Add Hindi widget translations, loaded only for visitors using Hindi. diff --git a/.changeset/identity-tokens.md b/.changeset/identity-tokens.md deleted file mode 100644 index f35b56b7..00000000 --- a/.changeset/identity-tokens.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@chatcops/server": minor -"@chatcops/widget": minor ---- - -Signed-in visitors. With `identity: { secret }` on the server, your site signs a `userToken` (an HS256 JWT with `sub`, `exp` and an optional `tier`) and the widget sends it with `/session` (`userToken` or `data-user-token`). The user id goes into the session token and is stored on the conversation, so the same user can resume it with a fresh token and nobody else can. `identity.tiers` gives a tier its own budgets. diff --git a/.changeset/ingest.md b/.changeset/ingest.md deleted file mode 100644 index 324f86b7..00000000 --- a/.changeset/ingest.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/ingest": minor ---- - -New package: `ingest()` builds a knowledge index from a site. It discovers pages from sitemaps (indexes and `.xml.gz` too), URL lists and folders of Markdown/MDX/HTML; fetches with conditional requests, a timeout and limited concurrency; extracts readable content as Markdown with Readability, after removing hidden elements, scripts and comments; chunks along headings without splitting code blocks or tables; embeds and writes to any `VectorStore`. A manifest in a `KeyValueStore` makes re-runs embed only what changed, `prune` never runs after a discovery error, and an index refuses an embedder other than the one that built it. diff --git a/.changeset/italian-widget-locale.md b/.changeset/italian-widget-locale.md deleted file mode 100644 index e898cf87..00000000 --- a/.changeset/italian-widget-locale.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/widget": patch ---- - -Add Italian widget translations, loaded only for visitors using Italian. diff --git a/.changeset/japanese-widget-locale.md b/.changeset/japanese-widget-locale.md deleted file mode 100644 index 4ba9759e..00000000 --- a/.changeset/japanese-widget-locale.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/widget": patch ---- - -Add Japanese widget translations, loaded only for visitors using Japanese. diff --git a/.changeset/javascript-assertion.md b/.changeset/javascript-assertion.md deleted file mode 100644 index 5ba2ccd6..00000000 --- a/.changeset/javascript-assertion.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/cli": minor ---- - -`javascript` assertion: point it at a module (relative to the eval file) and its default export is called with `(turn, conversation)`. Returns a boolean or `{ pass, reason?, score? }`, and may be async. A missing file, a module without a default function, or a throw inside it are failures with the file name in the reason. Modules are loaded once per run. diff --git a/.changeset/keyword-any-word.md b/.changeset/keyword-any-word.md deleted file mode 100644 index aecbea14..00000000 --- a/.changeset/keyword-any-word.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@chatcops/core": patch -"@chatcops/store-postgres": patch ---- - -Keyword search in the pgvector store now matches pages with any of the question's words, ranked by how well they match, instead of only pages with all of them. The storage conformance suite checks this for every store. diff --git a/.changeset/korean-widget-locale.md b/.changeset/korean-widget-locale.md deleted file mode 100644 index 0aecaa92..00000000 --- a/.changeset/korean-widget-locale.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/widget": patch ---- - -Add Korean widget translations, loaded only for visitors using Korean. diff --git a/.changeset/logger.md b/.changeset/logger.md deleted file mode 100644 index ea9098b6..00000000 --- a/.changeset/logger.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"@chatcops/core": minor -"@chatcops/server": minor ---- - -A `Logger` for everything ChatCops writes: `logger` in the server config gets startup notes, refused requests and every error the server handles instead of throwing, each with a stable `event` name (`provider_error`, `tool_error`, `webhook_failed`, `origin_refused`, …). The default `consoleLogger()` prints the same `[chatcops] …` lines as before; `jsonLogger()` writes one JSON object per line, and any object with `debug`/`info`/`warn`/`error` works. Tools get the logger as `context.logger`, and `runTurn`, providers (`ProviderConfig.logger`), `ConversationManager` and `BufferedEventSink` take one too. - -**Tool errors:** when a tool throws, the model now sees only `Tool failed: `, and the full error is logged as `tool_error`. Before, the thrown message went to the model, which could repeat a database error or a connection string to the visitor. Return `{ success: false, message }` to tell the model something it can pass on. Timeouts and cancelled replies keep their messages. - -Console lines for errors that come with an error object no longer end in a colon (`[chatcops] Provider error` and the error), and `describeBudgets` and `describeSecurity` no longer start with `[chatcops] `, since the logger adds it. diff --git a/.changeset/logical-widget-styles.md b/.changeset/logical-widget-styles.md deleted file mode 100644 index 2f1358db..00000000 --- a/.changeset/logical-widget-styles.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@chatcops/widget': patch ---- - -Use logical CSS properties for widget styles so layout and message bubbles adapt to right-to-left languages. diff --git a/.changeset/mobile-fullscreen-scroll-lock.md b/.changeset/mobile-fullscreen-scroll-lock.md deleted file mode 100644 index 1ddf9e4e..00000000 --- a/.changeset/mobile-fullscreen-scroll-lock.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/widget": patch ---- - -Lock document scrolling on mobile screens (640px and below) when the chat panel is open in full-screen mode, and restore original overflow on close or destroy. Update mobile breakpoint to 640px, add safe-area insets, and set mobile input font size to 16px to prevent auto-zooming on mobile devices. diff --git a/.changeset/parts-assertions.md b/.changeset/parts-assertions.md deleted file mode 100644 index 7876c97b..00000000 --- a/.changeset/parts-assertions.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/cli": minor ---- - -`chatcops test` has `cites` and `lead-captured` assertions, for the pages a reply cites and the leads a turn captures. diff --git a/.changeset/popup-focus-trap.md b/.changeset/popup-focus-trap.md deleted file mode 100644 index 18fa629b..00000000 --- a/.changeset/popup-focus-trap.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/widget": patch ---- - -Keep keyboard focus inside the open popup chat. diff --git a/.changeset/portuguese-widget-locale.md b/.changeset/portuguese-widget-locale.md deleted file mode 100644 index ea9034af..00000000 --- a/.changeset/portuguese-widget-locale.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/widget": patch ---- - -Add Portuguese widget translations, loaded only for visitors using Portuguese. diff --git a/.changeset/quiet-rivers-smile.md b/.changeset/quiet-rivers-smile.md deleted file mode 100644 index 74cd91d4..00000000 --- a/.changeset/quiet-rivers-smile.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/cli": minor ---- - -Add a grouped, more detailed pretty report for `chatcops test`, including the `--verbose` option. diff --git a/.changeset/quiet-vectors-smile.md b/.changeset/quiet-vectors-smile.md deleted file mode 100644 index 15d73f68..00000000 --- a/.changeset/quiet-vectors-smile.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/store-upstash-vector": minor ---- - -Add an Upstash Vector-backed store for ChatCops embedded page chunks. diff --git a/.changeset/respect-ingest-robots.md b/.changeset/respect-ingest-robots.md deleted file mode 100644 index dab293bd..00000000 --- a/.changeset/respect-ingest-robots.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@chatcops/ingest': minor ---- - -Respect robots.txt by default during ingestion, with per-origin policy caching, allow/disallow matching and crawl-delay scheduling. Add respectRobots to opt out for network sources; local files are unaffected. - -Report unavailable robots policies as per-origin errors and skip pruning during outages, instead of treating them as successful runs blocked by explicit rules. diff --git a/.changeset/retrieval.md b/.changeset/retrieval.md deleted file mode 100644 index 7874cc90..00000000 --- a/.changeset/retrieval.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"@chatcops/core": minor -"@chatcops/server": minor ---- - -Retrieval building blocks. `KnowledgeSource` has an optional `retrieve(query)` that returns chunks with their source page. When a source has it, the server calls it with the conversation so far, for follow-up questions, and gives the model every source's chunks as one numbered block, fenced as reference material that never contains instructions. Sources with only `getContext` work as before. - -New in core: the `Embedder`, `Retriever`, `RetrievedChunk` and `RetrievalQuery` types, `openaiEmbedder` (fetch only, `text-embedding-3-small` at 1024 dimensions by default, with retries on rate limits), `retrieverKnowledge` and `formatSources`. diff --git a/.changeset/retrievers.md b/.changeset/retrievers.md deleted file mode 100644 index bd09aed8..00000000 --- a/.changeset/retrievers.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/core": minor ---- - -Ready-made retrievers: `vectorRetriever` searches a vector store by meaning, and `hybridRetriever` also searches by words and merges both by rank (reciprocal rank fusion, k = 60), which finds product names and codes that meaning alone misses. Both take `candidates` and an optional `reranker` (new `Reranker` interface), and refuse an embedder whose vectors don't match the store's size. A short or follow-up question is searched together with the visitor's previous one (`retrievalQueryText`). `reciprocalRankFusion` is exported too. diff --git a/.changeset/rtl-widget-direction.md b/.changeset/rtl-widget-direction.md deleted file mode 100644 index ae6c5596..00000000 --- a/.changeset/rtl-widget-direction.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/widget": minor ---- - -Add locale-aware text direction and language attributes for RTL widget support. diff --git a/.changeset/spanish-widget-locale.md b/.changeset/spanish-widget-locale.md deleted file mode 100644 index 13aa33e7..00000000 --- a/.changeset/spanish-widget-locale.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/widget": patch ---- - -Add Spanish widget translations, loaded only for visitors using Spanish. diff --git a/.changeset/sqlite-vector-search.md b/.changeset/sqlite-vector-search.md deleted file mode 100644 index 7e0c6165..00000000 --- a/.changeset/sqlite-vector-search.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@chatcops/store-sqlite': minor ---- - -Add opt-in sqlite-vec vector storage with cosine similarity, metadata filtering, and FTS5 keyword search including CJK segmentation. diff --git a/.changeset/tidy-vectors-search.md b/.changeset/tidy-vectors-search.md deleted file mode 100644 index d897d7bd..00000000 --- a/.changeset/tidy-vectors-search.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@chatcops/store-postgres': minor ---- - -Add optional pgvector-backed vector storage with cosine and keyword search. diff --git a/.changeset/tool-call-assertions.md b/.changeset/tool-call-assertions.md deleted file mode 100644 index 37ecdb91..00000000 --- a/.changeset/tool-call-assertions.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/cli": minor ---- - -`chatcops test` has `calls-tool` and `no-tool-call` assertions, for checking that a turn calls a tool with expected arguments or makes no unexpected tool calls. diff --git a/.changeset/typed-widget-events.md b/.changeset/typed-widget-events.md deleted file mode 100644 index 23620b14..00000000 --- a/.changeset/typed-widget-events.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/widget": patch ---- - -`ChatCops.on()` and `widget.on()` type each handler by its event, so `on('message', (message) => ...)` gets a `MessageData` and `on('error', (error) => ...)` an `Error`. A handler typed `(...args: unknown[]) => void` still works. `WidgetEvents` and `MessageData` are exported. diff --git a/.changeset/ur-widget-locale.md b/.changeset/ur-widget-locale.md deleted file mode 100644 index 45503964..00000000 --- a/.changeset/ur-widget-locale.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/widget": patch ---- - -Add Urdu widget translations, loaded only for visitors using Urdu. diff --git a/.changeset/usage-assertions.md b/.changeset/usage-assertions.md deleted file mode 100644 index 6e797fdf..00000000 --- a/.changeset/usage-assertions.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/cli": minor ---- - -`chatcops test` has `tokens-under`, `latency-under` and `cost-under` assertions, to catch replies that get longer, slower or more expensive. diff --git a/.changeset/vector-store.md b/.changeset/vector-store.md deleted file mode 100644 index 6748ee09..00000000 --- a/.changeset/vector-store.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/core": minor ---- - -New `VectorStore` interface (`vectors` on `ChatCopsStorage`) for embedded chunks of a site's pages, with `upsert`, `query` (cosine similarity), an optional `keywordQuery` and `deleteBySource`. `memoryVectors({ dimensions })` keeps them in memory and does BM25 keyword search with `Intl.Segmenter`, so Japanese and Chinese work. `runStorageConformance` checks `vectors` when a store has them. The server doesn't search vectors yet. diff --git a/.changeset/voyage-embedder.md b/.changeset/voyage-embedder.md deleted file mode 100644 index d662c9dc..00000000 --- a/.changeset/voyage-embedder.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/core": minor ---- - -Add `voyageEmbedder`, which turns text into vectors with Voyage AI's embeddings API. It embeds documents and search queries the way Voyage recommends, batches requests, and retries rate limits and server errors. diff --git a/.changeset/warm-rerankers-rank.md b/.changeset/warm-rerankers-rank.md deleted file mode 100644 index c686062c..00000000 --- a/.changeset/warm-rerankers-rank.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/core": minor ---- - -Add `voyageReranker` for reranking retrieved chunks with Voyage AI's Reranker API. diff --git a/.changeset/welcome-bubble-button.md b/.changeset/welcome-bubble-button.md deleted file mode 100644 index d1ea0cfc..00000000 --- a/.changeset/welcome-bubble-button.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/widget": patch ---- - -Make the welcome bubble text keyboard-accessible. diff --git a/.changeset/welcome-bubble-delay.md b/.changeset/welcome-bubble-delay.md deleted file mode 100644 index acab9d99..00000000 --- a/.changeset/welcome-bubble-delay.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/widget": patch ---- - -A `data-welcome-bubble-delay` that isn't whole milliseconds, such as `3s`, now falls back to the default delay instead of being read as 3 ms. diff --git a/.changeset/widget-ai-disclosure.md b/.changeset/widget-ai-disclosure.md deleted file mode 100644 index 41775ec3..00000000 --- a/.changeset/widget-ai-disclosure.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/widget": minor ---- - -The chat now starts with a note that the visitor is talking to an AI ("You're chatting with an AI assistant. It can make mistakes."), as the EU AI Act asks (Article 50). It's on by default, stays first in the log (also after a new conversation), and has `role="note"`. `disclosure: { text, learnMoreUrl }` (or `data-disclosure-text`, `data-disclosure-url`) changes the wording and adds a link; `disclosure: false` (`data-disclosure="false"`) removes it and logs a console notice that telling visitors is then up to you. New locale strings: `disclosure`, `disclosureLearnMore`. diff --git a/.changeset/widget-api-methods.md b/.changeset/widget-api-methods.md deleted file mode 100644 index 32e9165e..00000000 --- a/.changeset/widget-api-methods.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/widget": minor ---- - -More of the widget API, on `window.ChatCops` (script tag builds) and the npm default export: `toggle()`, `sendMessage(text, { open? })` to send as the visitor from your own buttons, `newConversation()` to start fresh, `clear()` to also remove the saved transcript and pre-chat answers, `registerLocale(code, strings, { dir? })` for a language the widget doesn't ship, and `version`. With the script tag loader they work before the chat has loaded: the first call loads it. A reply still coming when the conversation is reset is stopped and never lands in the new one. `WidgetLocaleStrings` is exported for typing your strings. diff --git a/.changeset/widget-chunks.md b/.changeset/widget-chunks.md deleted file mode 100644 index 2fcac2d2..00000000 --- a/.changeset/widget-chunks.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@chatcops/widget": patch ---- - -The pre-chat form and the Turnstile helper are now separate files in `dist/chunks/`, loaded by the chat panel only on sites that use them. The panel is about 0.6 kB smaller for everyone else. Self-hosted sites need to copy `dist/chunks/` next to `chatcops.panel.js`. The single-file and ESM builds still include everything. - -If the pre-chat form's file fails to load, the chat opens without the form and logs the error, instead of leaving an empty panel. diff --git a/.changeset/widget-light-dark.md b/.changeset/widget-light-dark.md deleted file mode 100644 index a1ebe226..00000000 --- a/.changeset/widget-light-dark.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@chatcops/widget": minor ---- - -Light, dark and auto themes. `theme.mode` (`data-theme-mode`) is `auto` by default and follows the visitor's system setting, switching live; `light` and `dark` pin one. `theme.accentDark` (`data-accent-dark`) sets a separate accent for dark mode. - -**This changes how existing sites look:** the widget used to be dark everywhere, and is now light on light systems. Set `theme.mode: 'dark'` to keep the old look, which is exactly the dark preset. A config that sets `bgColor` or `textColor` without `mode` keeps the mode its colors were made for, so custom dark themes don't turn into light text on light panels. Errors and code blocks now use the `--cc-danger`, `--cc-code-bg` and `--cc-pre-bg` tokens. diff --git a/.changeset/widget-loader.md b/.changeset/widget-loader.md deleted file mode 100644 index 28e02f01..00000000 --- a/.changeset/widget-loader.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/widget": minor ---- - -The script tag build is now a small loader. `chatcops.min.js` (about 3 kB gzipped) draws the chat button and loads the chat panel (`chatcops.panel.js`, next to it) when the visitor hovers or clicks it, or when the page opens the chat, shows a welcome bubble or uses inline mode. Until then it reads no storage and makes no requests. The CDN snippet doesn't change. To self-host, copy both files, or use `chatcops.full.min.js`, which is the whole chat in one file as before. In the loader, `ChatCops.init()` returns nothing, and the other `ChatCops` methods work before and after the chat loads. diff --git a/.changeset/widget-locales.md b/.changeset/widget-locales.md deleted file mode 100644 index d39f90d6..00000000 --- a/.changeset/widget-locales.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/widget": minor ---- - -Translations can now ship as one file per language in `dist/locales/.js`. The script tag loader fetches the file for `locale` (or `data-locale`) next to the panel, at the same time as the panel, and falls back to English with a warning when there's none. Bundler users import `@chatcops/widget/locales/` and pass it as `strings`. A site's own `strings` still win over the translation. No languages ship yet; they're added one per pull request. diff --git a/.changeset/widget-mangle-private.md b/.changeset/widget-mangle-private.md deleted file mode 100644 index a40c47f8..00000000 --- a/.changeset/widget-mangle-private.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/widget": patch ---- - -The panel is about 240 B smaller gzipped (16.6 kB) and the single-file build about 300 B (18.62 kB): the minifier now also renames 55 more private class members, each checked to be used only inside its class. diff --git a/.changeset/widget-persistence.md b/.changeset/widget-persistence.md deleted file mode 100644 index 83c29955..00000000 --- a/.changeset/widget-persistence.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@chatcops/widget": minor ---- - -The widget no longer touches `localStorage` or `sessionStorage` before the visitor opens it. A popup reads its saved conversation on first open, and an inline chat reads it when it mounts. A welcome bubble with `showOnce` checks its flag only when it's due to show. - -New `persistence` option: `'local'` (the default, same as before), `'session'` (this tab only) or `'none'` (memory only, nothing is ever written). New `historyTtlDays` option drops saved conversations older than that many days, 30 by default. Both can be set from the script tag with `data-persistence` and `data-history-ttl-days`. - -The pre-chat form's answers are now saved with the conversation instead of per tab in `sessionStorage`, so they last and expire with it. A visitor who already has a saved conversation never gets the form on top of it, as before. - -`persistHistory` is deprecated. `persistHistory: false` still works and means `persistence: 'none'`. diff --git a/.changeset/widget-sources.md b/.changeset/widget-sources.md deleted file mode 100644 index f3c0ce42..00000000 --- a/.changeset/widget-sources.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/widget": minor ---- - -Show source pages under assistant replies. A reply that cites pages now shows a labelled "Sources" list of links beneath it. Sources survive a page reload. Non-http(s) URLs are never rendered as links. diff --git a/.changeset/widget-stream-render.md b/.changeset/widget-stream-render.md deleted file mode 100644 index 86255624..00000000 --- a/.changeset/widget-stream-render.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/widget": patch ---- - -Long replies stream without slowing the page down: finished paragraphs render once, and only the one being written re-renders, at most once a frame, instead of the whole reply on every chunk. The log follows new text only while it's scrolled to the bottom, so a visitor reading an earlier message isn't pulled away. The finished reply renders exactly as before. diff --git a/.changeset/widget-update.md b/.changeset/widget-update.md deleted file mode 100644 index 4b17dac7..00000000 --- a/.changeset/widget-update.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/widget": minor ---- - -`ChatCops.update(changes)` changes the running chat without loading it again: the theme (all but `position`), `branding`, `placeholder`, `strings`, `disclosure`, `welcomeMessage` and `suggestions`. Fields left out keep their current values. A chat that has only its welcome message shows the new one; once the visitor has written, the new welcome message and suggestions are used from the next conversation. In the script tag build, calls made before the chat loads are kept until it does, and the launcher takes the new theme right away. diff --git a/.changeset/widget-user-context.md b/.changeset/widget-user-context.md deleted file mode 100644 index 02c84300..00000000 --- a/.changeset/widget-user-context.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@chatcops/widget": minor -"@chatcops/server": minor -"@chatcops/core": minor ---- - -`ChatCops.setUser({ name, email, token })` and `ChatCops.setContext(data)`. `setUser` sets the signed-in visitor's identity token for the server, and sends `name` and `email` as visitor details with the first message of each conversation; switching users or `setUser(null)` clears the chat. `setContext` adds details for the next messages, such as `{ plan: 'Team' }`, sent as the new `pageContext.data` (at most 20 string fields), which the server shows the model as page details that aren't verified. With the script tag loader both are kept until the chat loads, without loading it early or touching storage. - -Visitor details are now sent again with the first message of a new conversation on a v1 server, which keeps them from that message. diff --git a/.changeset/workers-ai-embedder.md b/.changeset/workers-ai-embedder.md deleted file mode 100644 index 60146473..00000000 --- a/.changeset/workers-ai-embedder.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@chatcops/core": minor ---- - -Add `workersAiEmbedder` for Cloudflare Workers AI embeddings using the native `env.AI` binding (`@cf/baai/bge-m3` at 1024 dimensions by default), with automatic batching up to 100 texts and response validation. diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md new file mode 100644 index 00000000..d21eedc2 --- /dev/null +++ b/packages/cli/CHANGELOG.md @@ -0,0 +1,58 @@ +# @chatcops/cli + +## 0.1.0 + +### Minor Changes + +- aa0576d: `chatcops test` runs eval files against your bot: YAML conversations (`evals/**/*.chat.yaml`, or `.chat.ts`/`.chat.mjs` modules) with assertions on each reply. It uses the config's new `server` section and runs through the real request path with fresh in-memory storage, tool mocks, page context, locale, `repeat` and `passRate`. Options: `--filter` (name or `tag:x`), `--repeat`, `--concurrency`, `--reporter pretty|json` (repeatable) and `--json`. Exit 0 when all passed, 1 when some failed, 2 when it couldn't run. This first version has the `contains` assertion (and `not-contains`); more are coming. + + `ingest` and `search` now say what's missing from the config when they run, so a config with only `server` works for `chatcops test`. + + `globToRegExp` in `@chatcops/ingest`: `**/` now also matches no folder, so `docs/**/*.md` matches `docs/intro.md`. + +- a9c1c60: New package: the `chatcops` command. `chatcops ingest` builds or updates a knowledge index from `chatcops.config.ts` or `--source` (sitemaps, page URLs, folders), with `--dry-run`, `--max-pages`, `--concurrency`, `--prune`, `--force`, `--index` and `--json` (one JSON object per line). `chatcops search` shows what retrieval finds for a question. Both refuse an embedder other than the one the index was built with. Exit codes: 0 done, 1 finished with failed pages or discovery errors, 2 could not run. + + `ingest()` takes `maxPages`; a capped run never prunes. + +- 55b6e36: `chatcops test --record` saves every HTTP call the tests make (model, embeddings, tools that call APIs) to `__cassettes__/.jsonl`, and `--replay` answers them from there without the network. Replay is the default when `CI` is set; `--live` calls the APIs anyway. Calls are matched by a hash of their method, URL and body, so a changed prompt, model or tool list fails with where the request changed and a note to re-record, instead of passing on an old answer. Headers and key-like query parameters are never saved. +- 07de986: `judge` assertions in `chatcops test`: a model grades the reply against a rubric from 0 to 1 and passes at `threshold` (default 0.7). The default judge is the cheap model of a provider other than the bot's; `--judge-model provider:model` or `judge` in the config picks another. Without a key for it the run refuses to start, and every run prints the judge it used. Judge calls are recorded and replayed with the rest. + + `prices` in the config (US dollars per million tokens, by model id) gives each turn and judge call a cost, and the run prints what it spent. `--max-cost ` stops starting turns once a run has spent that much; it needs prices for the models in use. Reporters get a run summary (mode, judge, cost) in `onEnd`. + +- 30525e3: `javascript` assertion: point it at a module (relative to the eval file) and its default export is called with `(turn, conversation)`. Returns a boolean or `{ pass, reason?, score? }`, and may be async. A missing file, a module without a default function, or a throw inside it are failures with the file name in the reason. Modules are loaded once per run. +- f362c92: `chatcops test` has `cites` and `lead-captured` assertions, for the pages a reply cites and the leads a turn captures. +- c488287: Add a grouped, more detailed pretty report for `chatcops test`, including the `--verbose` option. +- 18a77bd: `chatcops test` has `calls-tool` and `no-tool-call` assertions, for checking that a turn calls a tool with expected arguments or makes no unexpected tool calls. +- c9ca76a: `chatcops test` has `tokens-under`, `latency-under` and `cost-under` assertions, to catch replies that get longer, slower or more expensive. + +### Patch Changes + +- af6345a: Eval recordings save response bodies over 4 kB gzipped in base64 (`encoding: 'gzip'`), so a streamed reply, which is one event per token, takes about a tenth of the space. Request bodies stay readable JSON, so a re-recording's diff still shows what changed. +- c5c81b0: `chatcops test` no longer stops the whole run when something throws while a reply is read, such as a knowledge source that can't reach its index (or a replay that has no recording for an embedding call). That test fails with `internal_error` and the message, and the other tests still run. +- Updated dependencies [5e34537] +- Updated dependencies [897f8e3] +- Updated dependencies [bd6f3c8] +- Updated dependencies [304f1df] +- Updated dependencies [3ee5fdc] +- Updated dependencies [aa0576d] +- Updated dependencies [b0bd38d] +- Updated dependencies [4e86624] +- Updated dependencies [a9c1c60] +- Updated dependencies [a714a12] +- Updated dependencies [cb360ad] +- Updated dependencies [8d6223d] +- Updated dependencies [31d67fb] +- Updated dependencies [eb4107c] +- Updated dependencies [f535508] +- Updated dependencies [e22060d] +- Updated dependencies [2e66f57] +- Updated dependencies [9d36629] +- Updated dependencies [d890cbe] +- Updated dependencies [100475b] +- Updated dependencies [7ecd228] +- Updated dependencies [b66fd9f] +- Updated dependencies [86085c0] +- Updated dependencies [a029c43] + - @chatcops/server@0.7.0 + - @chatcops/core@0.6.0 + - @chatcops/ingest@0.1.0 diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index a052bd21..614dd89d 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -1,5 +1,41 @@ # @chatcops/core +## 0.6.0 + +### Minor Changes + +- 897f8e3: Analytics events are named `noun.verb` now: `conversation.started`, `message.sent`, `message.received` and `lead.captured`, also exported as `ANALYTICS_EVENTS`. The old `noun:verb` names keep working until 1.0. `track()` and `getEvents()` read them as the new ones, stats count events a store saved under either, and `eventCounts` has both keys, so the numbers carry on across the upgrade. Stats gain `leadsCaptured`. `leadsCapture`, the same number, is deprecated. A custom `EventSink` now receives the new names. Webhook event names don't change. +- 304f1df: Add a Cloudflare Workers AI reranker for knowledge retrieval. +- 3ee5fdc: Add `cohereReranker` for reranking retrieved chunks with Cohere's Rerank API. +- b0bd38d: Answers now cite the pages they came from. Chunks from knowledge sources with `retrieve` are passed to the turn as `sources`, and each page the reply cites becomes a `source` part (once per page), streamed after the text and saved with the reply. Claude gets the chunks as `search_result` blocks and cites them natively; other providers get a numbered `` block and cite with `[n]`, and numbers that match no source are removed from the text. New in core: `sources` on `runTurn` and provider step params, `citations: 'native'` on providers, a `source` provider event, and `CitationParser`/`parseCitations`/`sourcePart`. +- 8d6223d: Add `geminiEmbedder` for embeddings via Google's Gemini batchEmbedContents API. +- e22060d: A `Logger` for everything ChatCops writes: `logger` in the server config gets startup notes, refused requests and every error the server handles instead of throwing, each with a stable `event` name (`provider_error`, `tool_error`, `webhook_failed`, `origin_refused`, …). The default `consoleLogger()` prints the same `[chatcops] …` lines as before; `jsonLogger()` writes one JSON object per line, and any object with `debug`/`info`/`warn`/`error` works. Tools get the logger as `context.logger`, and `runTurn`, providers (`ProviderConfig.logger`), `ConversationManager` and `BufferedEventSink` take one too. + + **Tool errors:** when a tool throws, the model now sees only `Tool failed: `, and the full error is logged as `tool_error`. Before, the thrown message went to the model, which could repeat a database error or a connection string to the visitor. Return `{ success: false, message }` to tell the model something it can pass on. Timeouts and cancelled replies keep their messages. + + Console lines for errors that come with an error object no longer end in a colon (`[chatcops] Provider error` and the error), and `describeBudgets` and `describeSecurity` no longer start with `[chatcops] `, since the logger adds it. + +- 9d36629: Retrieval building blocks. `KnowledgeSource` has an optional `retrieve(query)` that returns chunks with their source page. When a source has it, the server calls it with the conversation so far, for follow-up questions, and gives the model every source's chunks as one numbered block, fenced as reference material that never contains instructions. Sources with only `getContext` work as before. + + New in core: the `Embedder`, `Retriever`, `RetrievedChunk` and `RetrievalQuery` types, `openaiEmbedder` (fetch only, `text-embedding-3-small` at 1024 dimensions by default, with retries on rate limits), `retrieverKnowledge` and `formatSources`. + +- d890cbe: Ready-made retrievers: `vectorRetriever` searches a vector store by meaning, and `hybridRetriever` also searches by words and merges both by rank (reciprocal rank fusion, k = 60), which finds product names and codes that meaning alone misses. Both take `candidates` and an optional `reranker` (new `Reranker` interface), and refuse an embedder whose vectors don't match the store's size. A short or follow-up question is searched together with the visitor's previous one (`retrievalQueryText`). `reciprocalRankFusion` is exported too. +- 100475b: New `VectorStore` interface (`vectors` on `ChatCopsStorage`) for embedded chunks of a site's pages, with `upsert`, `query` (cosine similarity), an optional `keywordQuery` and `deleteBySource`. `memoryVectors({ dimensions })` keeps them in memory and does BM25 keyword search with `Intl.Segmenter`, so Japanese and Chinese work. `runStorageConformance` checks `vectors` when a store has them. The server doesn't search vectors yet. +- 7ecd228: Add `voyageEmbedder`, which turns text into vectors with Voyage AI's embeddings API. It embeds documents and search queries the way Voyage recommends, batches requests, and retries rate limits and server errors. +- b66fd9f: Add `voyageReranker` for reranking retrieved chunks with Voyage AI's Reranker API. +- 86085c0: `ChatCops.setUser({ name, email, token })` and `ChatCops.setContext(data)`. `setUser` sets the signed-in visitor's identity token for the server, and sends `name` and `email` as visitor details with the first message of each conversation; switching users or `setUser(null)` clears the chat. `setContext` adds details for the next messages, such as `{ plan: 'Team' }`, sent as the new `pageContext.data` (at most 20 string fields), which the server shows the model as page details that aren't verified. With the script tag loader both are kept until the chat loads, without loading it early or touching storage. + + Visitor details are now sent again with the first message of a new conversation on a v1 server, which keeps them from that message. + +- a029c43: Add `workersAiEmbedder` for Cloudflare Workers AI embeddings using the native `env.AI` binding (`@cf/baai/bge-m3` at 1024 dimensions by default), with automatic batching up to 100 texts and response validation. + +### Patch Changes + +- bd6f3c8: The Claude provider now uses `@anthropic-ai/sdk` 1.x, which talks to Claude's API version 2026-10-21. That version removed `temperature`, so it's never sent to Claude: a configured `temperature` logs one warning and is left out. Claude 4.7 and later, including the default `claude-haiku-5-5`, already ignored it. On older Claude models a lowered `temperature` no longer has an effect; use `effort` instead. +- 4e86624: Support Japanese and Chinese in TextKnowledgeSource and FAQKnowledgeSource using word segmentation. +- a714a12: `openaiEmbedder` now keeps `batchSize` between 1 and 2048 (what OpenAI accepts), so a value of 0 no longer loops forever. The OpenAI, Voyage and Gemini embedders share one implementation of retries and batching, with no change in behavior. +- f535508: Keyword search in the pgvector store now matches pages with any of the question's words, ranked by how well they match, instead of only pages with all of them. The storage conformance suite checks this for every store. + ## 0.5.0 ### Minor Changes diff --git a/packages/core/package.json b/packages/core/package.json index 5bc4b4e1..e6110bb0 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@chatcops/core", - "version": "0.5.0", + "version": "0.6.0", "description": "Core AI provider abstraction, tools, and knowledge base for ChatCops", "keywords": [ "chatcops", diff --git a/packages/ingest/CHANGELOG.md b/packages/ingest/CHANGELOG.md new file mode 100644 index 00000000..0bc13012 --- /dev/null +++ b/packages/ingest/CHANGELOG.md @@ -0,0 +1,41 @@ +# @chatcops/ingest + +## 0.1.0 + +### Minor Changes + +- a9c1c60: New package: the `chatcops` command. `chatcops ingest` builds or updates a knowledge index from `chatcops.config.ts` or `--source` (sitemaps, page URLs, folders), with `--dry-run`, `--max-pages`, `--concurrency`, `--prune`, `--force`, `--index` and `--json` (one JSON object per line). `chatcops search` shows what retrieval finds for a question. Both refuse an embedder other than the one the index was built with. Exit codes: 0 done, 1 finished with failed pages or discovery errors, 2 could not run. + + `ingest()` takes `maxPages`; a capped run never prunes. + +- eb4107c: New package: `ingest()` builds a knowledge index from a site. It discovers pages from sitemaps (indexes and `.xml.gz` too), URL lists and folders of Markdown/MDX/HTML; fetches with conditional requests, a timeout and limited concurrency; extracts readable content as Markdown with Readability, after removing hidden elements, scripts and comments; chunks along headings without splitting code blocks or tables; embeds and writes to any `VectorStore`. A manifest in a `KeyValueStore` makes re-runs embed only what changed, `prune` never runs after a discovery error, and an index refuses an embedder other than the one that built it. +- 2e66f57: Respect robots.txt by default during ingestion, with per-origin policy caching, allow/disallow matching and crawl-delay scheduling. Add respectRobots to opt out for network sources; local files are unaffected. + + Report unavailable robots policies as per-origin errors and skip pruning during outages, instead of treating them as successful runs blocked by explicit rules. + +### Patch Changes + +- aa0576d: `chatcops test` runs eval files against your bot: YAML conversations (`evals/**/*.chat.yaml`, or `.chat.ts`/`.chat.mjs` modules) with assertions on each reply. It uses the config's new `server` section and runs through the real request path with fresh in-memory storage, tool mocks, page context, locale, `repeat` and `passRate`. Options: `--filter` (name or `tag:x`), `--repeat`, `--concurrency`, `--reporter pretty|json` (repeatable) and `--json`. Exit 0 when all passed, 1 when some failed, 2 when it couldn't run. This first version has the `contains` assertion (and `not-contains`); more are coming. + + `ingest` and `search` now say what's missing from the config when they run, so a config with only `server` works for `chatcops test`. + + `globToRegExp` in `@chatcops/ingest`: `**/` now also matches no folder, so `docs/**/*.md` matches `docs/intro.md`. + +- Updated dependencies [897f8e3] +- Updated dependencies [bd6f3c8] +- Updated dependencies [304f1df] +- Updated dependencies [3ee5fdc] +- Updated dependencies [b0bd38d] +- Updated dependencies [4e86624] +- Updated dependencies [a714a12] +- Updated dependencies [8d6223d] +- Updated dependencies [f535508] +- Updated dependencies [e22060d] +- Updated dependencies [9d36629] +- Updated dependencies [d890cbe] +- Updated dependencies [100475b] +- Updated dependencies [7ecd228] +- Updated dependencies [b66fd9f] +- Updated dependencies [86085c0] +- Updated dependencies [a029c43] + - @chatcops/core@0.6.0 diff --git a/packages/server/CHANGELOG.md b/packages/server/CHANGELOG.md index 3d162482..ff08c424 100644 --- a/packages/server/CHANGELOG.md +++ b/packages/server/CHANGELOG.md @@ -1,5 +1,49 @@ # @chatcops/server +## 0.7.0 + +### Minor Changes + +- 897f8e3: Analytics events are named `noun.verb` now: `conversation.started`, `message.sent`, `message.received` and `lead.captured`, also exported as `ANALYTICS_EVENTS`. The old `noun:verb` names keep working until 1.0. `track()` and `getEvents()` read them as the new ones, stats count events a store saved under either, and `eventCounts` has both keys, so the numbers carry on across the upgrade. Stats gain `leadsCaptured`. `leadsCapture`, the same number, is deprecated. A custom `EventSink` now receives the new names. Webhook event names don't change. +- b0bd38d: Answers now cite the pages they came from. Chunks from knowledge sources with `retrieve` are passed to the turn as `sources`, and each page the reply cites becomes a `source` part (once per page), streamed after the text and saved with the reply. Claude gets the chunks as `search_result` blocks and cites them natively; other providers get a numbered `` block and cite with `[n]`, and numbers that match no source are removed from the text. New in core: `sources` on `runTurn` and provider step params, `citations: 'native'` on providers, a `source` provider event, and `CitationParser`/`parseCitations`/`sourcePart`. +- cb360ad: The types that make up a config are now exported, so a site can name them: `ThemeConfig`, `ThemeMode`, `PreChatField`, `PreChatFormConfig`, `Persistence`, `MessageStatus` and `MessageErrorType` from `@chatcops/widget`, and `TurnstileConfig` from `@chatcops/server`. +- 31d67fb: Signed-in visitors. With `identity: { secret }` on the server, your site signs a `userToken` (an HS256 JWT with `sub`, `exp` and an optional `tier`) and the widget sends it with `/session` (`userToken` or `data-user-token`). The user id goes into the session token and is stored on the conversation, so the same user can resume it with a fresh token and nobody else can. `identity.tiers` gives a tier its own budgets. +- e22060d: A `Logger` for everything ChatCops writes: `logger` in the server config gets startup notes, refused requests and every error the server handles instead of throwing, each with a stable `event` name (`provider_error`, `tool_error`, `webhook_failed`, `origin_refused`, …). The default `consoleLogger()` prints the same `[chatcops] …` lines as before; `jsonLogger()` writes one JSON object per line, and any object with `debug`/`info`/`warn`/`error` works. Tools get the logger as `context.logger`, and `runTurn`, providers (`ProviderConfig.logger`), `ConversationManager` and `BufferedEventSink` take one too. + + **Tool errors:** when a tool throws, the model now sees only `Tool failed: `, and the full error is logged as `tool_error`. Before, the thrown message went to the model, which could repeat a database error or a connection string to the visitor. Return `{ success: false, message }` to tell the model something it can pass on. Timeouts and cancelled replies keep their messages. + + Console lines for errors that come with an error object no longer end in a colon (`[chatcops] Provider error` and the error), and `describeBudgets` and `describeSecurity` no longer start with `[chatcops] `, since the logger adds it. + +- 9d36629: Retrieval building blocks. `KnowledgeSource` has an optional `retrieve(query)` that returns chunks with their source page. When a source has it, the server calls it with the conversation so far, for follow-up questions, and gives the model every source's chunks as one numbered block, fenced as reference material that never contains instructions. Sources with only `getContext` work as before. + + New in core: the `Embedder`, `Retriever`, `RetrievedChunk` and `RetrievalQuery` types, `openaiEmbedder` (fetch only, `text-embedding-3-small` at 1024 dimensions by default, with retries on rate limits), `retrieverKnowledge` and `formatSources`. + +- 86085c0: `ChatCops.setUser({ name, email, token })` and `ChatCops.setContext(data)`. `setUser` sets the signed-in visitor's identity token for the server, and sends `name` and `email` as visitor details with the first message of each conversation; switching users or `setUser(null)` clears the chat. `setContext` adds details for the next messages, such as `{ plan: 'Team' }`, sent as the new `pageContext.data` (at most 20 string fields), which the server shows the model as page details that aren't verified. With the script tag loader both are kept until the chat loads, without loading it early or touching storage. + + Visitor details are now sent again with the first message of a new conversation on a v1 server, which keeps them from that message. + +### Patch Changes + +- 5e34537: 405 responses now include `Allow: POST, OPTIONS`. +- Updated dependencies [897f8e3] +- Updated dependencies [bd6f3c8] +- Updated dependencies [304f1df] +- Updated dependencies [3ee5fdc] +- Updated dependencies [b0bd38d] +- Updated dependencies [4e86624] +- Updated dependencies [a714a12] +- Updated dependencies [8d6223d] +- Updated dependencies [f535508] +- Updated dependencies [e22060d] +- Updated dependencies [9d36629] +- Updated dependencies [d890cbe] +- Updated dependencies [100475b] +- Updated dependencies [7ecd228] +- Updated dependencies [b66fd9f] +- Updated dependencies [86085c0] +- Updated dependencies [a029c43] + - @chatcops/core@0.6.0 + ## 0.6.0 ### Minor Changes diff --git a/packages/server/package.json b/packages/server/package.json index 30a85eb6..3567357b 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "@chatcops/server", - "version": "0.6.0", + "version": "0.7.0", "description": "Server-side handler and adapters for ChatCops", "keywords": [ "chatcops", diff --git a/packages/store-cloudflare/CHANGELOG.md b/packages/store-cloudflare/CHANGELOG.md index ee0f7bb1..6c570136 100644 --- a/packages/store-cloudflare/CHANGELOG.md +++ b/packages/store-cloudflare/CHANGELOG.md @@ -1,5 +1,32 @@ # @chatcops/store-cloudflare +## 0.2.0 + +### Minor Changes + +- d651eea: Add optional Cloudflare Vectorize and D1 vector storage with semantic and keyword search. + +### Patch Changes + +- Updated dependencies [897f8e3] +- Updated dependencies [bd6f3c8] +- Updated dependencies [304f1df] +- Updated dependencies [3ee5fdc] +- Updated dependencies [b0bd38d] +- Updated dependencies [4e86624] +- Updated dependencies [a714a12] +- Updated dependencies [8d6223d] +- Updated dependencies [f535508] +- Updated dependencies [e22060d] +- Updated dependencies [9d36629] +- Updated dependencies [d890cbe] +- Updated dependencies [100475b] +- Updated dependencies [7ecd228] +- Updated dependencies [b66fd9f] +- Updated dependencies [86085c0] +- Updated dependencies [a029c43] + - @chatcops/core@0.6.0 + ## 0.1.0 ### Minor Changes diff --git a/packages/store-cloudflare/package.json b/packages/store-cloudflare/package.json index 559f3f19..d52f2b55 100644 --- a/packages/store-cloudflare/package.json +++ b/packages/store-cloudflare/package.json @@ -1,6 +1,6 @@ { "name": "@chatcops/store-cloudflare", - "version": "0.1.0", + "version": "0.2.0", "private": true, "description": "Cloudflare D1, KV and Durable Objects storage for ChatCops", "keywords": [ diff --git a/packages/store-postgres/CHANGELOG.md b/packages/store-postgres/CHANGELOG.md index 95dc25fb..e9ac2819 100644 --- a/packages/store-postgres/CHANGELOG.md +++ b/packages/store-postgres/CHANGELOG.md @@ -1,5 +1,33 @@ # @chatcops/store-postgres +## 0.2.0 + +### Minor Changes + +- 7e1e8cf: Add optional pgvector-backed vector storage with cosine and keyword search. + +### Patch Changes + +- f535508: Keyword search in the pgvector store now matches pages with any of the question's words, ranked by how well they match, instead of only pages with all of them. The storage conformance suite checks this for every store. +- Updated dependencies [897f8e3] +- Updated dependencies [bd6f3c8] +- Updated dependencies [304f1df] +- Updated dependencies [3ee5fdc] +- Updated dependencies [b0bd38d] +- Updated dependencies [4e86624] +- Updated dependencies [a714a12] +- Updated dependencies [8d6223d] +- Updated dependencies [f535508] +- Updated dependencies [e22060d] +- Updated dependencies [9d36629] +- Updated dependencies [d890cbe] +- Updated dependencies [100475b] +- Updated dependencies [7ecd228] +- Updated dependencies [b66fd9f] +- Updated dependencies [86085c0] +- Updated dependencies [a029c43] + - @chatcops/core@0.6.0 + ## 0.1.0 ### Minor Changes diff --git a/packages/store-postgres/package.json b/packages/store-postgres/package.json index b1e797cc..859c963a 100644 --- a/packages/store-postgres/package.json +++ b/packages/store-postgres/package.json @@ -1,6 +1,6 @@ { "name": "@chatcops/store-postgres", - "version": "0.1.0", + "version": "0.2.0", "private": true, "description": "Postgres storage for ChatCops: conversations, counters, keys and analytics events", "keywords": [ diff --git a/packages/store-redis/CHANGELOG.md b/packages/store-redis/CHANGELOG.md index daf8c221..f5d82940 100644 --- a/packages/store-redis/CHANGELOG.md +++ b/packages/store-redis/CHANGELOG.md @@ -1,5 +1,28 @@ # @chatcops/store-redis +## 0.2.0 + +### Patch Changes + +- Updated dependencies [897f8e3] +- Updated dependencies [bd6f3c8] +- Updated dependencies [304f1df] +- Updated dependencies [3ee5fdc] +- Updated dependencies [b0bd38d] +- Updated dependencies [4e86624] +- Updated dependencies [a714a12] +- Updated dependencies [8d6223d] +- Updated dependencies [f535508] +- Updated dependencies [e22060d] +- Updated dependencies [9d36629] +- Updated dependencies [d890cbe] +- Updated dependencies [100475b] +- Updated dependencies [7ecd228] +- Updated dependencies [b66fd9f] +- Updated dependencies [86085c0] +- Updated dependencies [a029c43] + - @chatcops/core@0.6.0 + ## 0.1.0 ### Minor Changes diff --git a/packages/store-redis/package.json b/packages/store-redis/package.json index d0659ae4..0d3751d7 100644 --- a/packages/store-redis/package.json +++ b/packages/store-redis/package.json @@ -1,6 +1,6 @@ { "name": "@chatcops/store-redis", - "version": "0.1.0", + "version": "0.2.0", "private": true, "description": "Redis and Upstash storage for ChatCops", "keywords": [ diff --git a/packages/store-sqlite/CHANGELOG.md b/packages/store-sqlite/CHANGELOG.md index 89178526..fe3efc8a 100644 --- a/packages/store-sqlite/CHANGELOG.md +++ b/packages/store-sqlite/CHANGELOG.md @@ -1,5 +1,32 @@ # @chatcops/store-sqlite +## 0.2.0 + +### Minor Changes + +- 3d50e5b: Add opt-in sqlite-vec vector storage with cosine similarity, metadata filtering, and FTS5 keyword search including CJK segmentation. + +### Patch Changes + +- Updated dependencies [897f8e3] +- Updated dependencies [bd6f3c8] +- Updated dependencies [304f1df] +- Updated dependencies [3ee5fdc] +- Updated dependencies [b0bd38d] +- Updated dependencies [4e86624] +- Updated dependencies [a714a12] +- Updated dependencies [8d6223d] +- Updated dependencies [f535508] +- Updated dependencies [e22060d] +- Updated dependencies [9d36629] +- Updated dependencies [d890cbe] +- Updated dependencies [100475b] +- Updated dependencies [7ecd228] +- Updated dependencies [b66fd9f] +- Updated dependencies [86085c0] +- Updated dependencies [a029c43] + - @chatcops/core@0.6.0 + ## 0.1.0 ### Minor Changes diff --git a/packages/store-sqlite/package.json b/packages/store-sqlite/package.json index 24c318f8..49b99a25 100644 --- a/packages/store-sqlite/package.json +++ b/packages/store-sqlite/package.json @@ -1,6 +1,6 @@ { "name": "@chatcops/store-sqlite", - "version": "0.1.0", + "version": "0.2.0", "private": true, "description": "SQLite storage for ChatCops single-server deployments", "keywords": [ @@ -35,7 +35,9 @@ "sqlite-vec": "^0.1.9" }, "peerDependenciesMeta": { - "sqlite-vec": { "optional": true } + "sqlite-vec": { + "optional": true + } }, "devDependencies": { "@chatcops/core": "workspace:*", diff --git a/packages/store-upstash-vector/CHANGELOG.md b/packages/store-upstash-vector/CHANGELOG.md index f8782296..d4d7ef4d 100644 --- a/packages/store-upstash-vector/CHANGELOG.md +++ b/packages/store-upstash-vector/CHANGELOG.md @@ -4,4 +4,31 @@ ### Minor Changes +- ce1d0e3: Add an Upstash Vector-backed store for ChatCops embedded page chunks. + +### Patch Changes + +- Updated dependencies [897f8e3] +- Updated dependencies [bd6f3c8] +- Updated dependencies [304f1df] +- Updated dependencies [3ee5fdc] +- Updated dependencies [b0bd38d] +- Updated dependencies [4e86624] +- Updated dependencies [a714a12] +- Updated dependencies [8d6223d] +- Updated dependencies [f535508] +- Updated dependencies [e22060d] +- Updated dependencies [9d36629] +- Updated dependencies [d890cbe] +- Updated dependencies [100475b] +- Updated dependencies [7ecd228] +- Updated dependencies [b66fd9f] +- Updated dependencies [86085c0] +- Updated dependencies [a029c43] + - @chatcops/core@0.6.0 + +## 0.1.0 + +### Minor Changes + - Add Upstash Vector-backed storage for ChatCops embedded page chunks. diff --git a/packages/store-upstash-vector/package.json b/packages/store-upstash-vector/package.json index d528990f..8ba5ba78 100644 --- a/packages/store-upstash-vector/package.json +++ b/packages/store-upstash-vector/package.json @@ -3,20 +3,53 @@ "version": "0.1.0", "private": true, "description": "Upstash Vector storage for ChatCops", - "keywords": ["chatcops", "storage", "vector", "upstash"], + "keywords": [ + "chatcops", + "storage", + "vector", + "upstash" + ], "homepage": "https://chat.codercops.com", "bugs": "https://github.com/codercops/chatcops/issues", "type": "module", "main": "dist/index.js", "types": "dist/index.d.ts", - "exports": { ".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" } }, - "files": ["dist"], + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js" + } + }, + "files": [ + "dist" + ], "sideEffects": false, - "scripts": { "build": "tsc", "typecheck": "tsc -p tsconfig.test.json --noEmit", "test": "vitest run", "test:watch": "vitest" }, - "peerDependencies": { "@chatcops/core": "workspace:^", "@upstash/vector": "^1.2.3" }, - "devDependencies": { "@chatcops/core": "workspace:*", "@upstash/vector": "^1.2.3", "typescript": "^5.7.0", "vitest": "^4.1.11" }, - "repository": { "type": "git", "url": "git+https://github.com/codercops/chatcops.git", "directory": "packages/store-upstash-vector" }, - "publishConfig": { "access": "public" }, + "scripts": { + "build": "tsc", + "typecheck": "tsc -p tsconfig.test.json --noEmit", + "test": "vitest run", + "test:watch": "vitest" + }, + "peerDependencies": { + "@chatcops/core": "workspace:^", + "@upstash/vector": "^1.2.3" + }, + "devDependencies": { + "@chatcops/core": "workspace:*", + "@upstash/vector": "^1.2.3", + "typescript": "^5.7.0", + "vitest": "^4.1.11" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/codercops/chatcops.git", + "directory": "packages/store-upstash-vector" + }, + "publishConfig": { + "access": "public" + }, "license": "MIT", - "engines": { "node": ">=22" } + "engines": { + "node": ">=22" + } } diff --git a/packages/widget/CHANGELOG.md b/packages/widget/CHANGELOG.md index 525df650..4d635f27 100644 --- a/packages/widget/CHANGELOG.md +++ b/packages/widget/CHANGELOG.md @@ -1,5 +1,67 @@ # @chatcops/widget +## 0.7.0 + +### Minor Changes + +- b93e221: Add configurable suggested question buttons to new widget conversations. +- cb360ad: The types that make up a config are now exported, so a site can name them: `ThemeConfig`, `ThemeMode`, `PreChatField`, `PreChatFormConfig`, `Persistence`, `MessageStatus` and `MessageErrorType` from `@chatcops/widget`, and `TurnstileConfig` from `@chatcops/server`. +- 31d67fb: Signed-in visitors. With `identity: { secret }` on the server, your site signs a `userToken` (an HS256 JWT with `sub`, `exp` and an optional `tier`) and the widget sends it with `/session` (`userToken` or `data-user-token`). The user id goes into the session token and is stored on the conversation, so the same user can resume it with a fresh token and nobody else can. `identity.tiers` gives a tier its own budgets. +- d9c8ea6: Add locale-aware text direction and language attributes for RTL widget support. +- 3ff10e0: The chat now starts with a note that the visitor is talking to an AI ("You're chatting with an AI assistant. It can make mistakes."), as the EU AI Act asks (Article 50). It's on by default, stays first in the log (also after a new conversation), and has `role="note"`. `disclosure: { text, learnMoreUrl }` (or `data-disclosure-text`, `data-disclosure-url`) changes the wording and adds a link; `disclosure: false` (`data-disclosure="false"`) removes it and logs a console notice that telling visitors is then up to you. New locale strings: `disclosure`, `disclosureLearnMore`. +- da756fe: More of the widget API, on `window.ChatCops` (script tag builds) and the npm default export: `toggle()`, `sendMessage(text, { open? })` to send as the visitor from your own buttons, `newConversation()` to start fresh, `clear()` to also remove the saved transcript and pre-chat answers, `registerLocale(code, strings, { dir? })` for a language the widget doesn't ship, and `version`. With the script tag loader they work before the chat has loaded: the first call loads it. A reply still coming when the conversation is reset is stopped and never lands in the new one. `WidgetLocaleStrings` is exported for typing your strings. +- cc19259: Light, dark and auto themes. `theme.mode` (`data-theme-mode`) is `auto` by default and follows the visitor's system setting, switching live; `light` and `dark` pin one. `theme.accentDark` (`data-accent-dark`) sets a separate accent for dark mode. + + **This changes how existing sites look:** the widget used to be dark everywhere, and is now light on light systems. Set `theme.mode: 'dark'` to keep the old look, which is exactly the dark preset. A config that sets `bgColor` or `textColor` without `mode` keeps the mode its colors were made for, so custom dark themes don't turn into light text on light panels. Errors and code blocks now use the `--cc-danger`, `--cc-code-bg` and `--cc-pre-bg` tokens. + +- f1ff788: The script tag build is now a small loader. `chatcops.min.js` (about 3 kB gzipped) draws the chat button and loads the chat panel (`chatcops.panel.js`, next to it) when the visitor hovers or clicks it, or when the page opens the chat, shows a welcome bubble or uses inline mode. Until then it reads no storage and makes no requests. The CDN snippet doesn't change. To self-host, copy both files, or use `chatcops.full.min.js`, which is the whole chat in one file as before. In the loader, `ChatCops.init()` returns nothing, and the other `ChatCops` methods work before and after the chat loads. +- d09b5a7: Translations can now ship as one file per language in `dist/locales/.js`. The script tag loader fetches the file for `locale` (or `data-locale`) next to the panel, at the same time as the panel, and falls back to English with a warning when there's none. Bundler users import `@chatcops/widget/locales/` and pass it as `strings`. A site's own `strings` still win over the translation. No languages ship yet; they're added one per pull request. +- 59e8486: The widget no longer touches `localStorage` or `sessionStorage` before the visitor opens it. A popup reads its saved conversation on first open, and an inline chat reads it when it mounts. A welcome bubble with `showOnce` checks its flag only when it's due to show. + + New `persistence` option: `'local'` (the default, same as before), `'session'` (this tab only) or `'none'` (memory only, nothing is ever written). New `historyTtlDays` option drops saved conversations older than that many days, 30 by default. Both can be set from the script tag with `data-persistence` and `data-history-ttl-days`. + + The pre-chat form's answers are now saved with the conversation instead of per tab in `sessionStorage`, so they last and expire with it. A visitor who already has a saved conversation never gets the form on top of it, as before. + + `persistHistory` is deprecated. `persistHistory: false` still works and means `persistence: 'none'`. + +- cf184c7: Show source pages under assistant replies. A reply that cites pages now shows a labelled "Sources" list of links beneath it. Sources survive a page reload. Non-http(s) URLs are never rendered as links. +- 08b4647: `ChatCops.update(changes)` changes the running chat without loading it again: the theme (all but `position`), `branding`, `placeholder`, `strings`, `disclosure`, `welcomeMessage` and `suggestions`. Fields left out keep their current values. A chat that has only its welcome message shows the new one; once the visitor has written, the new welcome message and suggestions are used from the next conversation. In the script tag build, calls made before the chat loads are kept until it does, and the launcher takes the new theme right away. +- 86085c0: `ChatCops.setUser({ name, email, token })` and `ChatCops.setContext(data)`. `setUser` sets the signed-in visitor's identity token for the server, and sends `name` and `email` as visitor details with the first message of each conversation; switching users or `setUser(null)` clears the chat. `setContext` adds details for the next messages, such as `{ plan: 'Team' }`, sent as the new `pageContext.data` (at most 20 string fields), which the server shows the model as page details that aren't verified. With the script tag loader both are kept until the chat loads, without loading it early or touching storage. + + Visitor details are now sent again with the first message of a new conversation on a v1 server, which keeps them from that message. + +### Patch Changes + +- 5ef0242: Announce completed assistant replies once for screen readers. +- b8c5ed6: Add Arabic widget translations, loaded only for visitors using Arabic. +- d6c857f: Show unread reply count in the launcher badge and accessible name. +- 15d5b10: Add Simplified Chinese widget translations, loaded only for visitors using Chinese. +- 095829b: Add Dutch widget translations, loaded only for visitors using Dutch. +- 75903b4: Add source labels and AI disclosure translations to 11 widget locales. +- 83e0d3f: Add --cc-focus-ring on :host for visible keyboard focus indicators across widget controls. +- 9632988: Add French widget translations, loaded only for visitors using French. +- 458fb3c: Add German widget translations, loaded only for visitors using German. +- 316f625: Add Hebrew widget translations, loaded only for visitors using Hebrew. +- fa8df0d: Add Hindi widget translations, loaded only for visitors using Hindi. +- 26a4086: Add Italian widget translations, loaded only for visitors using Italian. +- 2c1f49a: Add Japanese widget translations, loaded only for visitors using Japanese. +- 3896eb0: Add Korean widget translations, loaded only for visitors using Korean. +- 95f58dd: Use logical CSS properties for widget styles so layout and message bubbles adapt to right-to-left languages. +- 983d7d6: Lock document scrolling on mobile screens (640px and below) when the chat panel is open in full-screen mode, and restore original overflow on close or destroy. Update mobile breakpoint to 640px, add safe-area insets, and set mobile input font size to 16px to prevent auto-zooming on mobile devices. +- 82822a6: Keep keyboard focus inside the open popup chat. +- f73ecf8: Add Portuguese widget translations, loaded only for visitors using Portuguese. +- 535e23a: Add Spanish widget translations, loaded only for visitors using Spanish. +- 6cf2674: `ChatCops.on()` and `widget.on()` type each handler by its event, so `on('message', (message) => ...)` gets a `MessageData` and `on('error', (error) => ...)` an `Error`. A handler typed `(...args: unknown[]) => void` still works. `WidgetEvents` and `MessageData` are exported. +- e51822f: Add Urdu widget translations, loaded only for visitors using Urdu. +- 7665dcb: Make the welcome bubble text keyboard-accessible. +- f5416e2: A `data-welcome-bubble-delay` that isn't whole milliseconds, such as `3s`, now falls back to the default delay instead of being read as 3 ms. +- 0d35733: The pre-chat form and the Turnstile helper are now separate files in `dist/chunks/`, loaded by the chat panel only on sites that use them. The panel is about 0.6 kB smaller for everyone else. Self-hosted sites need to copy `dist/chunks/` next to `chatcops.panel.js`. The single-file and ESM builds still include everything. + + If the pre-chat form's file fails to load, the chat opens without the form and logs the error, instead of leaving an empty panel. + +- f4ce2c8: The panel is about 240 B smaller gzipped (16.6 kB) and the single-file build about 300 B (18.62 kB): the minifier now also renames 55 more private class members, each checked to be used only inside its class. +- 5dc1fc6: Long replies stream without slowing the page down: finished paragraphs render once, and only the one being written re-renders, at most once a frame, instead of the whole reply on every chunk. The log follows new text only while it's scrolled to the bottom, so a visitor reading an earlier message isn't pulled away. The finished reply renders exactly as before. + ## 0.6.0 ### Minor Changes diff --git a/packages/widget/package.json b/packages/widget/package.json index d98eaced..9452fb25 100644 --- a/packages/widget/package.json +++ b/packages/widget/package.json @@ -1,6 +1,6 @@ { "name": "@chatcops/widget", - "version": "0.6.0", + "version": "0.7.0", "description": "Embeddable AI chatbot widget - zero dependencies, Shadow DOM isolated", "keywords": [ "chatcops", diff --git a/website/CHANGELOG.md b/website/CHANGELOG.md index fc5595cc..6599b73f 100644 --- a/website/CHANGELOG.md +++ b/website/CHANGELOG.md @@ -1,5 +1,71 @@ # @chatcops/website +## 0.0.6 + +### Patch Changes + +- Updated dependencies [5e34537] +- Updated dependencies [897f8e3] +- Updated dependencies [5ef0242] +- Updated dependencies [bd6f3c8] +- Updated dependencies [b8c5ed6] +- Updated dependencies [d6c857f] +- Updated dependencies [b93e221] +- Updated dependencies [304f1df] +- Updated dependencies [3ee5fdc] +- Updated dependencies [15d5b10] +- Updated dependencies [b0bd38d] +- Updated dependencies [4e86624] +- Updated dependencies [d651eea] +- Updated dependencies [095829b] +- Updated dependencies [75903b4] +- Updated dependencies [a714a12] +- Updated dependencies [cb360ad] +- Updated dependencies [83e0d3f] +- Updated dependencies [9632988] +- Updated dependencies [8d6223d] +- Updated dependencies [458fb3c] +- Updated dependencies [316f625] +- Updated dependencies [fa8df0d] +- Updated dependencies [31d67fb] +- Updated dependencies [26a4086] +- Updated dependencies [2c1f49a] +- Updated dependencies [f535508] +- Updated dependencies [3896eb0] +- Updated dependencies [e22060d] +- Updated dependencies [95f58dd] +- Updated dependencies [983d7d6] +- Updated dependencies [82822a6] +- Updated dependencies [f73ecf8] +- Updated dependencies [9d36629] +- Updated dependencies [d890cbe] +- Updated dependencies [d9c8ea6] +- Updated dependencies [535e23a] +- Updated dependencies [6cf2674] +- Updated dependencies [e51822f] +- Updated dependencies [100475b] +- Updated dependencies [7ecd228] +- Updated dependencies [b66fd9f] +- Updated dependencies [7665dcb] +- Updated dependencies [f5416e2] +- Updated dependencies [3ff10e0] +- Updated dependencies [da756fe] +- Updated dependencies [0d35733] +- Updated dependencies [cc19259] +- Updated dependencies [f1ff788] +- Updated dependencies [d09b5a7] +- Updated dependencies [f4ce2c8] +- Updated dependencies [59e8486] +- Updated dependencies [cf184c7] +- Updated dependencies [5dc1fc6] +- Updated dependencies [08b4647] +- Updated dependencies [86085c0] +- Updated dependencies [a029c43] + - @chatcops/server@0.7.0 + - @chatcops/core@0.6.0 + - @chatcops/widget@0.7.0 + - @chatcops/store-cloudflare@1.0.0 + ## 0.0.5 ### Patch Changes diff --git a/website/package.json b/website/package.json index 3dd06ca6..6d67a533 100644 --- a/website/package.json +++ b/website/package.json @@ -1,6 +1,6 @@ { "name": "@chatcops/website", - "version": "0.0.5", + "version": "0.0.6", "private": true, "type": "module", "scripts": {