Skip to content

feat(examples): add TanStack AI chat() guardrails example - #207

Merged
davidmytton merged 5 commits into
mainfrom
david/cursor/tanstack-agent-guardrails
Sep 3, 2026
Merged

feat(examples): add TanStack AI chat() guardrails example#207
davidmytton merged 5 commits into
mainfrom
david/cursor/tanstack-agent-guardrails

Conversation

@davidmytton

Copy link
Copy Markdown
Collaborator

Adds examples/tanstack-agent: a small Node chat({ middleware }) support agent protected by @arcjet/guard/tanstack-ai/v0 (arcjet-js#6260).

Inbound guard() runs before chat(). guardMiddleware is first in the middleware list so onBeforeToolCall rate-limits lookups and scans free-text note args for PII. Default DENY is { type: "skip", result: ArcjetDenialResult }. Correlation is a caller-owned sessionId — never ctx.threadId.

The adapter is on main but not on npm yet, so @arcjet/guard and @arcjet/transport (./http2) are vendored from d730d57. Repin once @arcjet/guard/tanstack-ai/v0 publishes.

import { guardMiddleware, tanstackAiContext } from "@arcjet/guard/tanstack-ai/v0";
import { chat } from "@tanstack/ai";

const appContext = { sessionId: conversationId };
const ctx = tanstackAiContext({ context: appContext });

const inbound = await arcjet.guard({
  label: "message.received",
  rules: [detectInjection(text)],
  ...ctx,
});
if (inbound.conclusion === "DENY" || inbound.hasFailedOpen()) {
  return; // do not call chat()
}

const stream = chat({
  adapter,
  messages,
  tools: [lookupOrder],
  context: appContext,
  middleware: [
    guardMiddleware(arcjet, {
      action: ({ toolName }) => `${toolName}.invoked`,
      sessionId: conversationId,
      rules: ({ input }) => [
        lookupLimit({ key: `order:${input.orderId}`, requested: 1 }),
        ...(input.note ? [detectPii(input.note)] : []),
      ],
    }),
  ],
});

Docs: /guards/tanstack-ai/. Run examples/tanstack-agent with ARCJET_KEY and AI_GATEWAY_API_KEY.

Open in Web Open in Cursor 

cursoragent and others added 4 commits August 31, 2026 14:25
Add a standalone tanstack-agent that vendors unpublished
@arcjet/guard/tanstack-ai/v0 from arcjet-js@3e81a91c and demonstrates
guardMiddleware first, tanstackAiContext, and inbound guard() before chat().

Co-authored-by: David Mytton <davidmytton@users.noreply.github.com>
Use streamToText so RUN_ERROR is not an empty 200, accept TANSTACK_MODEL
via openaiCompatibleText, register the example in the root compose file,
and return 400 for invalid JSON and Zod errors.

Co-authored-by: David Mytton <davidmytton@users.noreply.github.com>
Repin the unpublished tanstack-ai/v0 adapter to the merge commit on
arcjet-js main (d730d57). npm still does not export the subpath.

Co-authored-by: David Mytton <davidmytton@users.noreply.github.com>
Guard on main imports @arcjet/transport/http2, which npm 1.11.0 does
not export. Pin both packages to the #6260 merge SHA so the example
can start.

Co-authored-by: David Mytton <davidmytton@users.noreply.github.com>
@socket-security

socket-security Bot commented Sep 1, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednpm/​@​tanstack/​ai-openai@​0.22.310010010098100
Addednpm/​@​tanstack/​ai@​0.52.010010010098100

View full report

@socket-security

socket-security Bot commented Sep 1, 2026

Copy link
Copy Markdown

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn Medium
Network access: npm @tanstack/ai-openai in module globalThis["fetch"]

Module: globalThis["fetch"]

Location: Package overview

From: examples/tanstack-agent/package-lock.jsonnpm/@tanstack/ai-openai@0.22.3

ℹ Read more on: This package | This alert | What is network access?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should remove all network access that is functionally unnecessary. Consumers should audit network access to ensure legitimate use.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/@tanstack/ai-openai@0.22.3. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn Low
Environment variable access: npm @tanstack/ai-utils

Location: Package overview

From: examples/tanstack-agent/package-lock.jsonnpm/@tanstack/ai@0.52.0npm/@tanstack/ai-openai@0.22.3npm/@tanstack/ai-utils@0.4.0

ℹ Read more on: This package | This alert | What is environment variable access?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should be clear about which environment variables they access, and care should be taken to ensure they only access environment variables they claim to.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/@tanstack/ai-utils@0.4.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

@arcjet-review arcjet-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arcjet Review — 🟡 Medium Risk

Decision: Approved

Rationale: Self-contained example addition. New Node HTTP server has input validation (zod), body size cap (32 KiB), message length cap (2000), and clear README warnings that this is a local demo without auth. No hardcoded secrets. The vendored @arcjet/guard and @arcjet/transport packages are pinned to a documented arcjet-js commit (d730d57) with SOURCE.txt attribution and are only used inside the example. Escalation triggers fire (Dockerfile, compose.yaml, package.json) but each is scoped to the new example directory and doesn't touch shared infra. Approving despite Medium risk because the changes are isolated to an example, security caveats are clearly documented, and the guardrails logic itself (inbound guard() + hasFailedOpen check, guardMiddleware first, default-skip DENY) matches the documented @arcjet/guard/tanstack-ai/v0 patterns.

Summary of Changes

Adds examples/tanstack-agent: a Node HTTP server + minimal HTML page demonstrating TanStack AI chat() protected by Arcjet Guard's tanstack-ai/v0 adapter. Inbound prompt-injection screening runs before chat(); guardMiddleware runs first for tool-call rate limiting and PII detection on free-text args. Because @arcjet/guard/tanstack-ai/v0 is not yet on npm, @arcjet/guard and @arcjet/transport are vendored from arcjet-js@d730d57. Also registers the example in the top-level compose.yaml, README, and prepare-to-publish.ts.

Escalation Triggers

  • Dependency Changes: New examples/tanstack-agent/package.json declares dependencies including file:./vendor/... refs and an overrides block for @arcjet/transport.
  • CI/CD Pipeline: New Dockerfile for the example (scoped to examples/tanstack-agent, not shared CI).
  • Infrastructure: New examples/tanstack-agent/compose.yaml and an include entry in the top-level compose.yaml.

Notes

PR exceeds the 1000-line threshold, but ~2500+ of the added lines are vendored README/LICENSE/SKILL.md content from arcjet-js@d730d57 (documented in vendor/SOURCE.txt), not novel logic. The reviewable new code (index.ts, lib/agent.ts, lib/arcjet.ts, index.html, tsconfig/Dockerfile/compose) is small and self-contained.

Path filtering: 95 files excluded by ignore paths. 27 of 122 files included in review.

Review: 762d75cd | Model: anthropic/claude-opus-4-7 | Powered by Arcjet Review

Comment thread examples/tanstack-agent/index.ts
Comment thread examples/tanstack-agent/index.ts
Comment thread examples/tanstack-agent/lib/agent.ts
Comment thread examples/tanstack-agent/index.ts
Comment thread examples/tanstack-agent/vendor/arcjet-guard/package.json
@arcjet-review arcjet-review Bot removed ai-review-in-progress needs review Awaiting human review labels Sep 1, 2026
Fail fast on missing model keys, destroy oversized request streams,
return 400 for invalid conversation ids, log inbound guard throws,
and version the vendor packages so they do not collide with npm 1.11.0.

Co-authored-by: David Mytton <davidmytton@users.noreply.github.com>
@davidmytton
davidmytton added this pull request to the merge queue Sep 3, 2026
Merged via the queue into main with commit e62fd79 Sep 3, 2026
23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants