npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

n8n-nodes-imoxto

v0.1.6

Published

Is for now just a wrapper of https://www.npmjs.com/package/n8n-nodes-deepseek-reasoner

Readme

A fork of https://www.npmjs.com/package/n8n-nodes-deepseek-reasoner but with cost reporting as i couldnt find a way to get all types of token counts in n8n.

Layout

src/credentials/AscDeepSeekReasonerApi.credentials.ts   credential definition
src/nodes/AscDeepSeekReasoner/AscDeepSeekReasoner.node.ts   node + ChatDeepSeekReasoner chat model
test/unit/                                              offline tests (stubbed fetch)
test/live/                                              tests against the real APIs (DeepSeek and Z.ai)

Fallback model

The node takes an optional Fallback Model alongside Model. Leave it empty and nothing changes.

Set it, and once the configured model has used up its whole retry budget (Max Retries in Options), the same request is sent again with the fallback model — same credential, same Base URL, same body, only model differs. That includes thinking, reasoning_effort, the bound tools and the replayed reasoning_content on assistant turns, so a failover mid-conversation still satisfies DeepSeek's reasoning echo. A fallback that is blank, or that just repeats the primary, is ignored.

Only a model that has exhausted its retries is abandoned, so a transient blip retries on the model you asked for rather than silently switching. If the fallback fails too, its error is the one that surfaces.

Which model gets reported

Whatever answered. The provider's own model field is passed through untouched; when a provider omits it, the node fills in the model it sent. That value reaches n8n through llmOutput.model_name, the generation's generationInfo.model and the message's response_metadata.model_name.

So the Output Report URL payload always names a real model, and gains two fields next to the response body:

| field | meaning | | --- | --- | | model | the model the provider says served the request | | requested_model | the model the node asked for on the successful attempt — the fallback, after a failover | | fallback_used | true when the fallback answered |

Custom Body Fields are merged last, so they still win on a name clash. Only the successful call is reported: a failed attempt returns no usage, so it is not billable and not posted.

On Max Tokens

On a thinking model max_tokens covers the reasoning too. When the budget runs out mid-thought the API returns finish_reason: "length", an empty content and a reasoning_content that stops partway. The node used to fall back to that reasoning as the answer, which leaked the raw chain of thought into the output.

A final answer cut off at max_tokens now follows On Max Tokens in Options. Only the debug setting ever outputs the reasoning:

| setting | result | | --- | --- | | Throw Error | the call fails with a message saying whether it ran out while reasoning or partway through the answer; catch it with the Agent's On Error → Continue (using error output) | | Return Empty | empty answer | | Return Partial Content (default) | whatever answer text arrived before the cut-off, which may be empty or end mid-sentence | | Return Reasoning (Debug) | the cut-off reasoning and any partial answer, raw, under labels — for finding out why it ran out |

The debug output looks like this:

[Hit the Max Tokens limit (8192) before it finished reasoning]

Reasoning:
The user wants 17*23. I should break it down: 17*20 = 340, then

Partial answer:
...

Tool-call turns are passed back to the agent unchanged whatever the setting. The reasoning is still kept in history so the next turn echoes it. With the debug setting, a chat memory node stores the debug text as the assistant's reply, so the next turn of that conversation sees it — use it while investigating, not in production.

Scripts

| script | what it does | | --- | --- | | npm run build | compile src/ to dist/ and copy node icons | | npm run build:compare | same, but emits to dist2/ for diffing against the shipped dist/ | | npm run typecheck | type-check sources and tests without emitting | | npm test | unit tests (no network) | | npm run test:live | live tests against DeepSeek and Z.ai | | npm run test:all | both | | npm run test:coverage | unit tests with V8 coverage into coverage/ |

Live tests

test/live/ bills real accounts. Every case runs against each provider in test/live/providers.ts, so both endpoints get identical coverage. Keys go in .env (see .env.example):

DEEPSEEK_API_KEY=sk-...
Z_API_KEY=...
# optional overrides
DEEPSEEK_BASE_URL=https://api.deepseek.com
DEEPSEEK_TEST_MODEL=deepseek-flash
Z_BASE_URL=https://api.z.ai/api/paas/v4
Z_TEST_MODEL=glm-5.3-flash

A provider skips itself when its key is unset, and RUN_LIVE_TESTS=0 forces all of them off.

Provider differences

Both endpoints speak the same dialect (thinking: { type } on the request, reasoning_content on the response), so the node drives them unmodified — only the credential's Base URL changes. Two behaviours differ, and providers.ts records them as flags the live suite asserts:

| | DeepSeek | Z.ai (glm-5.3-flash) | | --- | --- | --- | | Rejects a thinking-mode turn that dropped reasoning_content | yes — the reason this node exists | no, it is tolerated | | Accepts thinking: {type: 'disabled'} | yes | no — HTTP 400 code 1210, "This model always engages in thinking and cannot be disabled" |

So Enable Thinking = off does not work against glm-5.3-flash: the node states the disable explicitly and the model rejects it. reasoning_effort accepts low, high and max there; anything else is a 400.

DeepSeek renamed its models

GET /models on DeepSeek now lists deepseek-flash and deepseek-v4-pro. The old deepseek-v4-flash still works, but as an alias: the request succeeds and the response reports model: "deepseek-flash". The node passes that through rather than echoing the name it sent, so reporting names the model that was actually billed — providers.ts pins the alias and the live suite asserts it.

The node's Model parameter still defaults to deepseek-v4-flash, which therefore keeps working. Worth changing to deepseek-flash the next time the node's defaults are revised.

dist vs dist2

src/ was reconstructed from the JavaScript that used to be committed under dist/. test/unit/build-parity.test.ts recompiles to dist2/ and asserts the emitted JavaScript still matches that original line for line, apart from an explicit allow-list of intended changes. The baseline is read from git at commit 67cdf52, so it keeps working now that dist/ is built rather than committed.