Skip to content

Commit 72c25c9

Browse files
authored
feat(typescript-client): Deno compatibility (#607)
* feat(typescript-client): add Deno compatibility - Switch build from tsc to tsup for dual CJS + ESM output with proper exports field - Add deno_setup.ts preload that injects Jest-compatible globals (describe/test/expect) via @std/testing/bdd and @std/expect - Fix generated client.gen.ts: exclude hey-api internal `client` field from RequestInit spread to avoid conflict with Deno.HttpClient - Add test:deno npm script using --unstable-sloppy-imports and --preload - Add test-typescript-client-deno CI job using denoland/setup-deno@v2 (v2.x) - Update docs: rename page to TypeScript / JavaScript Client, add Deno installation section * feat: add Deno compatibility to ai-sdk and chat integrations - Switch ai-sdk and chat builds from tsc to tsup (ESM bundle, eliminates extension-less import issues in Deno) - Add deno.json import map to ai-sdk redirecting 'vitest' to a custom vitest-compat.ts shim and bare npm specifiers to npm: URLs - Add vitest-compat.ts shim implementing vi.fn()/vi.spyOn()/vi.mocked() using @std/expect's Symbol.for("@mock") interface so toHaveBeenCalledWith and other mock matchers work under Deno - Add test:deno script to ai-sdk (all 30 tests pass under Deno) * ci: add Deno test job for ai-sdk integration Adds a new test-ai-sdk-integration-deno CI job that runs the ai-sdk unit tests under Deno LTS, verifying Deno compatibility of the package. * fix: remove broken link to non-existent n8n blog post in streamlit post * fix: patch client.gen.ts for Deno compatibility during generation Add a post-generation patch step to generate-clients.sh that removes the hey-api internal 'client' field from the RequestInit spread in client.gen.ts. Deno's Request constructor rejects 'client' because it conflicts with the Deno.HttpClient option name.
1 parent 8c378b9 commit 72c25c9

19 files changed

Lines changed: 3220 additions & 590 deletions

File tree

.github/workflows/test.yml

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,30 @@ jobs:
9898
working-directory: ./hindsight-integrations/ai-sdk
9999
run: npm run build
100100

101+
test-ai-sdk-integration-deno:
102+
runs-on: ubuntu-latest
103+
104+
steps:
105+
- uses: actions/checkout@v6
106+
107+
- name: Set up Deno
108+
uses: denoland/setup-deno@v2
109+
with:
110+
deno-version: v2.x
111+
112+
- name: Set up Node.js
113+
uses: actions/setup-node@v6
114+
with:
115+
node-version: '22'
116+
117+
- name: Install dependencies
118+
working-directory: ./hindsight-integrations/ai-sdk
119+
run: npm ci
120+
121+
- name: Run tests (Deno)
122+
working-directory: ./hindsight-integrations/ai-sdk
123+
run: npm run test:deno
124+
101125
build-chat-integration:
102126
runs-on: ubuntu-latest
103127

@@ -683,6 +707,119 @@ jobs:
683707
echo "=== API Server Logs ==="
684708
cat /tmp/api-server.log || echo "No API server log found"
685709
710+
test-typescript-client-deno:
711+
runs-on: ubuntu-latest
712+
env:
713+
HINDSIGHT_API_LLM_PROVIDER: vertexai
714+
HINDSIGHT_API_LLM_VERTEXAI_SERVICE_ACCOUNT_KEY: /tmp/gcp-credentials.json
715+
HINDSIGHT_API_LLM_MODEL: google/gemini-2.5-flash-lite
716+
HINDSIGHT_API_URL: http://localhost:8888
717+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
718+
719+
steps:
720+
- uses: actions/checkout@v6
721+
722+
- name: Setup GCP credentials
723+
run: |
724+
printf '%s' '${{ secrets.GCP_VERTEXAI_CREDENTIALS }}' > /tmp/gcp-credentials.json
725+
PROJECT_ID=$(jq -r '.project_id' /tmp/gcp-credentials.json)
726+
echo "HINDSIGHT_API_LLM_VERTEXAI_PROJECT_ID=$PROJECT_ID" >> $GITHUB_ENV
727+
728+
- name: Install uv
729+
uses: astral-sh/setup-uv@v7
730+
with:
731+
enable-cache: true
732+
prune-cache: false
733+
734+
- name: Set up Python
735+
uses: actions/setup-python@v6
736+
with:
737+
python-version-file: ".python-version"
738+
739+
- name: Set up Node.js
740+
uses: actions/setup-node@v6
741+
with:
742+
node-version: '20'
743+
cache: 'npm'
744+
cache-dependency-path: package-lock.json
745+
746+
- name: Set up Deno
747+
uses: denoland/setup-deno@v2
748+
with:
749+
deno-version: v2.x
750+
751+
- name: Build API
752+
working-directory: ./hindsight-api-slim
753+
run: uv build
754+
755+
- name: Install API dependencies
756+
working-directory: ./hindsight-api-slim
757+
run: uv sync --frozen --all-extras --index-strategy unsafe-best-match
758+
759+
- name: Install TypeScript client dependencies
760+
working-directory: ./hindsight-clients/typescript
761+
run: npm ci
762+
763+
- name: Build TypeScript client
764+
working-directory: ./hindsight-clients/typescript
765+
run: npm run build
766+
767+
- name: Cache HuggingFace models
768+
uses: actions/cache@v5
769+
with:
770+
path: ~/.cache/huggingface
771+
key: ${{ runner.os }}-huggingface-${{ hashFiles('hindsight-api-slim/pyproject.toml') }}
772+
restore-keys: |
773+
${{ runner.os }}-huggingface-
774+
775+
- name: Pre-download models
776+
working-directory: ./hindsight-api-slim
777+
run: |
778+
uv run python -c "
779+
from sentence_transformers import SentenceTransformer, CrossEncoder
780+
print('Downloading embedding model...')
781+
SentenceTransformer('BAAI/bge-small-en-v1.5')
782+
print('Downloading cross-encoder model...')
783+
CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2')
784+
print('Models downloaded successfully')
785+
"
786+
787+
- name: Create .env file
788+
run: |
789+
cat > .env << EOF
790+
HINDSIGHT_API_LLM_PROVIDER=${{ env.HINDSIGHT_API_LLM_PROVIDER }}
791+
HINDSIGHT_API_LLM_MODEL=${{ env.HINDSIGHT_API_LLM_MODEL }}
792+
HINDSIGHT_API_LLM_VERTEXAI_SERVICE_ACCOUNT_KEY=/tmp/gcp-credentials.json
793+
HINDSIGHT_API_LLM_VERTEXAI_PROJECT_ID=$HINDSIGHT_API_LLM_VERTEXAI_PROJECT_ID
794+
EOF
795+
796+
- name: Start API server
797+
run: |
798+
./scripts/dev/start-api.sh > /tmp/api-server.log 2>&1 &
799+
echo "Waiting for API server to be ready..."
800+
for i in {1..120}; do
801+
if curl -sf http://localhost:8888/health > /dev/null 2>&1; then
802+
echo "API server is ready after ${i}s"
803+
break
804+
fi
805+
if [ $i -eq 120 ]; then
806+
echo "API server failed to start after 120s"
807+
cat /tmp/api-server.log
808+
exit 1
809+
fi
810+
sleep 1
811+
done
812+
813+
- name: Run TypeScript client tests (Deno)
814+
working-directory: ./hindsight-clients/typescript
815+
run: npm run test:deno
816+
817+
- name: Show API server logs
818+
if: always()
819+
run: |
820+
echo "=== API Server Logs ==="
821+
cat /tmp/api-server.log || echo "No API server log found"
822+
686823
build-rust-cli-arm64:
687824
runs-on: ubuntu-24.04-arm
688825

deno.lock

Lines changed: 139 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

hindsight-clients/typescript/generated/client/client.gen.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,11 @@ export const createClient = (config: Config = {}): Client => {
7878
const request: Client["request"] = async (options) => {
7979
// @ts-expect-error
8080
const { opts, url } = await beforeRequest(options);
81+
// Exclude hey-api internal fields that conflict with Deno's RequestInit.client
82+
const { client: _client, ...optsForRequest } = opts as typeof opts & { client?: unknown };
8183
const requestInit: ReqInit = {
8284
redirect: "follow",
83-
...opts,
85+
...optsForRequest,
8486
body: getValidRequestBody(opts),
8587
};
8688

hindsight-clients/typescript/package.json

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,23 @@
22
"name": "@vectorize-io/hindsight-client",
33
"version": "0.4.18",
44
"description": "TypeScript client for Hindsight - Semantic memory system with personality-driven thinking",
5-
"main": "./dist/src/index.js",
6-
"types": "./dist/src/index.d.ts",
5+
"main": "./dist/index.js",
6+
"module": "./dist/index.mjs",
7+
"types": "./dist/index.d.ts",
8+
"exports": {
9+
".": {
10+
"types": "./dist/index.d.ts",
11+
"import": "./dist/index.mjs",
12+
"require": "./dist/index.js"
13+
}
14+
},
715
"scripts": {
8-
"build": "tsc",
16+
"build": "tsup",
917
"clean": "rm -rf dist",
1018
"generate": "npx @hey-api/openapi-ts",
1119
"prepublishOnly": "npm run build",
12-
"test": "jest"
20+
"test": "jest",
21+
"test:deno": "deno test --no-check --allow-env --allow-net --unstable-sloppy-imports --preload=tests/deno_setup.ts tests/main_operations.test.ts"
1322
},
1423
"keywords": [
1524
"hindsight",
@@ -31,6 +40,7 @@
3140
"@types/node": "^20.0.0",
3241
"jest": "^29.0.0",
3342
"ts-jest": "^29.0.0",
43+
"tsup": "^8.5.1",
3444
"typescript": "^5.0.0"
3545
},
3646
"files": [
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* Preload script for running Jest-style tests under Deno.
3+
* Injects Jest-compatible globals (describe, test, beforeAll, expect)
4+
* using Deno's standard library BDD and expect modules.
5+
*
6+
* Usage:
7+
* deno test --allow-env --allow-net --unstable-sloppy-imports \
8+
* --preload=tests/deno_setup.ts tests/
9+
*/
10+
11+
import { beforeAll, beforeEach, afterAll, afterEach, describe, it } from "jsr:@std/testing/bdd";
12+
import { expect } from "jsr:@std/expect";
13+
14+
Object.assign(globalThis, {
15+
describe,
16+
test: it,
17+
it,
18+
beforeAll,
19+
beforeEach,
20+
afterAll,
21+
afterEach,
22+
expect,
23+
});
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { defineConfig } from 'tsup';
2+
3+
export default defineConfig({
4+
entry: ['src/index.ts'],
5+
format: ['cjs', 'esm'],
6+
dts: true,
7+
outDir: 'dist',
8+
clean: true,
9+
sourcemap: true,
10+
// Bundle all relative imports (src + generated) into the output
11+
bundle: true,
12+
});

hindsight-docs/blog/2026-03-17-streamlit-chatbot-memory.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ export HINDSIGHT_API_LLM_API_KEY=YOUR_OPENAI_KEY
140140
hindsight-api
141141
```
142142

143-
> **Note:** You can also use [Hindsight Cloud](https://ui.hindsight.vectorize.io/signup) instead of self-hosting — just change the `base_url` to `https://api.hindsight.vectorize.io` and add your API key. See the [n8n integration guide](/blog/2026/03/16/n8n-memory-workflows) for details on Cloud vs. self-hosted setup.
143+
> **Note:** You can also use [Hindsight Cloud](https://ui.hindsight.vectorize.io/signup) instead of self-hosting — just change the `base_url` to `https://api.hindsight.vectorize.io` and add your API key.
144144
145145
Now wire Hindsight into the chat. The key pattern: use [`@st.cache_resource`](https://docs.streamlit.io/develop/api-reference/caching-and-state/st.cache_resource) to initialize the client once, not on every re-run.
146146

0 commit comments

Comments
 (0)