Skip to main content

Squillify development is paused indefinitely. Read why, and discover what this experiment achieved. Read the story

MicroSkills Reference

Retrieved Chunk Deduplicator

knowledge.deduplicate_chunks

ProductionBounded custom (Class B)Deterministicbest-effortmoderatev1.0.0
No network

Overview

Retrieval from several sources returns the same passage more than once, and paying to embed or prompt with it twice is waste. Send the chunks you retrieved and we hand back the survivors in their original order plus a removal report saying which chunk was a duplicate of which, and how close they were. Three modes: byte-identical text, text identical after normalising case, whitespace, punctuation and Unicode form, or near-duplicate by word-shingle Jaccard overlap against a threshold you choose. You also choose which member of a duplicate group survives — the first, the highest scoring, or the longest. Near-duplicate detection is a threshold judgement rather than a fact, which is why the mode is yours to pick and the similarity comes back with every removal. Reach for data.detect_duplicates instead when you are matching short record fields, where edit distance is the right measure.

Retrieval across several sources returns the same passage repeatedly, and every copy costs tokens in the prompt that follows. Removing them needs a decision about how close counts as the same and which copy to keep, and both belong to you — so both are settings, and every removal comes back with the evidence behind it.

Reliability

BEST_EFFORT, and the reason is worth understanding: byte-identical and normalised matching are facts, but a Jaccard overlap of 0.62 is only a duplicate because you said 0.5 was the line. Every removal therefore carries its similarity so you can audit the threshold you chose. Runs are deterministic — the same chunks, mode and settings always produce the same survivors, ties included, and nothing here reads a clock or a random number. Clustering is a single forward pass: with A similar to B and B similar to C but A not similar to C, A survives, B is removed as a duplicate of A, and C survives, because the only survivor C was measured against was A. Failures, none of which get better on their own: DEDUPE_CHUNKS_INVALID means chunks was empty, an entry was not an object, an id or text was missing or mistyped, a score was not finite, or an entry carried a property we do not accept — fix the entry named in the error and retry; DEDUPE_ID_DUPLICATE means two entries share an id, and the error says which position repeated it; DEDUPE_MODE_UNSUPPORTED means mode, keep, blockBy or normalization.unicodeForm named something that does not exist, and the accepted values come back with the error; DEDUPE_THRESHOLD_REQUIRED means you asked for SHINGLE_JACCARD without a threshold; DEDUPE_THRESHOLD_INVALID means the threshold was outside 0.5 to 1.0, or you sent one under a mode that does not use it; DEDUPE_LIMIT_EXCEEDED means more than 10000 chunks or a chunk text over 200000 characters — deduplicate the set in parts; DEDUPE_COMPARISON_LIMIT_EXCEEDED means the comparison would take more than 2000000 shingle-pair operations, and the error carries the number needed — set blockBy to LENGTH_BUCKET, raise shingleSize, or split the set; DEDUPE_OUTPUT_TOO_LARGE means the survivors could carry more than 1000000 characters of text between them, which we refuse rather than shorten.

Context footprint

Survivors carry their text, so the response is at most the size of the set you sent, capped at 1000000 characters across all of them. The removal report carries ids and numbers only. Both together are bounded by the 10000-chunk ceiling. A successful call costs 1 execution credit.

When to use it

After retrieval and before packing or embedding, when the same passage can reach you more than once.

When you are matching short record fields, when you need the chunks ranked, or when duplicates should be merged rather than dropped.

Powered by Squillify's own implementation of the published Jaccard index over word shingles, with SHA-256 content grouping for the exact modes. No third-party similarity engine and no model is involved.

Scope

Note
Drop duplicate and near-duplicate chunks from a retrieved set, keeping one member of each group and reporting every removal with its reason.

Non-goals

  • Does not use edit distance — chunk similarity is a set problem, not a field problem
  • Does not rank, re-order or score the survivors
  • Does not merge two near-duplicates into one chunk
  • Does not chain matches transitively across a whole cluster
  • Does not fetch, store or index anything

Properties

IdempotentRetry safeStreaming supportedFile input supportedRequires external service

Capabilities

data-transformationtext-processing

Cost & billing

Flat rate per invocation

MetercallsBillable onsuccessCost per call1 credit

File handling

Accepts file_refProduces file_refMax input2 MB

How we handle your data

Sensitive output possible
What this means

This skill may receive sensitive content and may return submitted, transformed, extracted, or reformatted content.

Squillify guarantees
  • Runs inside Squillify
  • This skill runs inside Squillify.
  • Payloads are not sent to an external service by this skill.
  • Squillify does not permanently store submitted payloads.
  • Telemetry records metadata only, not submitted content.
  • Submitted payloads are not used for training.
  • Submitted payloads are not reviewed by humans.
  • This skill does not target sensitive data.
  • The response may contain submitted or transformed content.
Your responsibility

Squillify does not determine whether submitted content is sensitive. Your application is responsible for deciding what data it is allowed to submit. Your application is responsible for securing the response.

Read the Microskill Data Handling Policy

Input schema

FieldTypeRequiredDescription
chunksarrayYesFrom 1 through 10000 closed chunks {id, text} plus optional score and ordinal.
modestringNoHow duplicates are judged; omit it for EXACT.
normalizationobjectNoClosed flattening applied before NORMALIZED and SHINGLE_JACCARD comparison; omit it for NFKC, collapseWhitespace true, caseFold true and stripPunctuation false.
thresholdnumberNoRequired unless mode is not SHINGLE_JACCARD; Jaccard overlap from 0.5 through 1.0 with no default.
shingleSizeintegerNoWords per shingle from 2 through 8; omit it for 5.
keepstringNoWhich member of a duplicate group survives; omit it for FIRST.
blockBystringNoHow SHINGLE_JACCARD pairs are blocked; omit it for NONE.

Output schema

FieldTypeRequiredDescription
chunksarrayYesSurvivors in the relative order you sent them, each a closed {id, text} object with optional score; this is the filtered set, not the candidate list.
removedarrayYesOne closed removal per dropped chunk in arrival order, with ids, mode, optional similarity and reasonCode.
summaryobjectYesClosed counts and settings receipt with inputCount, keptCount, removedCount, mode, optional threshold, shingleSize, keep, blockBy, normalization, comparisons and truncated.

API contract

POST /v1/execute
curl
curl -sS -X POST "$BASE/v1/execute" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' -d '{"skillKey":"knowledge.deduplicate_chunks","input":{"chunks":[{"id":"c1","text":"Refunds within 30 days.","score":0.9},{"id":"c2","text":"refunds within 30 days","score":0.4}],"mode":"NORMALIZED","keep":"HIGHEST_SCORE"}}'
Integrations
TypeScript SDK
import { Squillify } from "@squillify/sdk";

const sq = new Squillify({ apiKey: process.env.SQUILLIFY_API_KEY });

const { output } = await sq.execute("knowledge.deduplicate_chunks", {"chunks":[{"text":"We refund an unused subscription within 30 days.","score":0.91,"id":"a"},{"text":"A refund needs the original order id.","score":0.74,"id":"b"},{"text":"We refund an unused subscription within 30 days.","score":0.55,"id":"c"}],"mode":"EXACT"});

Errors

CodeHTTPRetryableDescription
VALIDATION_ERROR400NoThe request payload failed schema validation.
UNAUTHORIZED401NoMissing or invalid API key.
SKILL_NOT_ACCESSIBLE403NoThe API key is not granted access to this skill.
SKILL_NOT_AVAILABLE_FOR_PLAN403NoThis skill is not included in your current plan.
PLAN_ELIGIBILITY_UNAVAILABLE503YesPlan eligibility could not be decided. Retry after backoff.
SKILL_NOT_FOUND404NoThe requested skill or version does not exist.
TENANT_RATE_LIMITED429YesRequest rate limit exceeded. Retry after backoff.
QUOTA_EXCEEDED429YesPlan quota exhausted. Retryable once the quota period resets.
EXECUTION_TIMEOUT504YesExecution exceeded the allowed time budget.
DEDUPE_CHUNKS_INVALID400NoThe request payload failed this skill's input validation.
DEDUPE_ID_DUPLICATE400NoThe request payload failed this skill's input validation.
DEDUPE_MODE_UNSUPPORTED400NoThe skill does not support the requested variant.
DEDUPE_THRESHOLD_REQUIRED400NoThe request payload failed this skill's input validation.
DEDUPE_THRESHOLD_INVALID400NoThe request payload failed this skill's input validation.
DEDUPE_LIMIT_EXCEEDED429NoA size, quota, rate, or time limit was exceeded.
DEDUPE_COMPARISON_LIMIT_EXCEEDED429NoA size, quota, rate, or time limit was exceeded.
DEDUPE_OUTPUT_TOO_LARGE429NoA size, quota, rate, or time limit was exceeded.

Other limits

LimitValue
Recommended inline bytes32 KiB

Limitations

  • Does not use edit distance — chunk similarity is a set problem, not a field problem
  • Does not rank, re-order or score the survivors
  • Does not merge two near-duplicates into one chunk
  • Does not chain matches transitively across a whole cluster
  • Does not fetch, store or index anything
  • Matching customer records or short field values, where data.detect_duplicates fits
  • Deciding which chunks are most relevant, which knowledge.rank_bm25 answers
  • Merging duplicates into a single combined chunk

How to call

POST /v1/execute (requires authentication)

Request bodyjson
{
  "skillKey": "knowledge.deduplicate_chunks",
  "input": {
    "chunks": [
      {
        "text": "We refund an unused subscription within 30 days.",
        "score": 0.91,
        "id": "a"
      },
      {
        "text": "A refund needs the original order id.",
        "score": 0.74,
        "id": "b"
      },
      {
        "text": "We refund an unused subscription within 30 days.",
        "score": 0.55,
        "id": "c"
      }
    ],
    "mode": "EXACT"
  }
}

Examples

Two byte-identical chunks, the earlier one kept

Inputjson
{
  "chunks": [
    {
      "text": "We refund an unused subscription within 30 days.",
      "score": 0.91,
      "id": "a"
    },
    {
      "text": "A refund needs the original order id.",
      "score": 0.74,
      "id": "b"
    },
    {
      "text": "We refund an unused subscription within 30 days.",
      "score": 0.55,
      "id": "c"
    }
  ],
  "mode": "EXACT"
}
Expected outputjson
{
  "removed": [
    {
      "id": "c",
      "duplicateOfId": "a",
      "mode": "EXACT",
      "reasonCode": "EXACT_MATCH"
    }
  ],
  "summary": {
    "inputCount": 3,
    "keptCount": 2,
    "removedCount": 1,
    "mode": "EXACT",
    "shingleSize": 5,
    "keep": "FIRST",
    "blockBy": "NONE",
    "normalization": {
      "caseFold": true,
      "collapseWhitespace": true,
      "stripPunctuation": false,
      "unicodeForm": "NFKC"
    },
    "comparisons": 0,
    "truncated": false
  },
  "chunks": [
    {
      "id": "a",
      "text": "We refund an unused subscription within 30 days.",
      "score": 0.91
    },
    {
      "id": "b",
      "text": "A refund needs the original order id.",
      "score": 0.74
    }
  ]
}
Tip
Under EXACT the two identical chunks form one group, keep FIRST keeps the earlier of them, and the removal says which survivor it duplicates.

Near-duplicates found by word-shingle overlap

Inputjson
{
  "chunks": [
    {
      "id": "first",
      "text": "We refund an unused subscription within 30 days of the charge."
    },
    {
      "id": "second",
      "text": "We refund an unused subscription within 30 days of the payment."
    },
    {
      "id": "third",
      "text": "Partial months are never refunded under any circumstances."
    }
  ],
  "threshold": 0.5,
  "mode": "SHINGLE_JACCARD",
  "keep": "FIRST",
  "shingleSize": 3
}
Expected outputjson
{
  "removed": [
    {
      "id": "second",
      "duplicateOfId": "first",
      "mode": "SHINGLE_JACCARD",
      "similarity": 0.8,
      "reasonCode": "SIMILARITY_ABOVE_THRESHOLD"
    }
  ],
  "summary": {
    "inputCount": 3,
    "keptCount": 2,
    "removedCount": 1,
    "mode": "SHINGLE_JACCARD",
    "threshold": 0.5,
    "shingleSize": 3,
    "keep": "FIRST",
    "blockBy": "NONE",
    "normalization": {
      "caseFold": true,
      "collapseWhitespace": true,
      "stripPunctuation": false,
      "unicodeForm": "NFKC"
    },
    "comparisons": 15,
    "truncated": false
  },
  "chunks": [
    {
      "id": "first",
      "text": "We refund an unused subscription within 30 days of the charge."
    },
    {
      "id": "third",
      "text": "Partial months are never refunded under any circumstances."
    }
  ]
}
Tip
The first two sentences differ in one word, so their three-word shingles overlap well above 0.5 and the later one is removed with its similarity attached; the third sentence shares nothing and survives.
  • Collapse the same passage returned by two retrievers before packing a prompt
  • Drop re-formatted copies of a document that differ only in whitespace and case
  • Find near-duplicate chunks in a knowledge base before an embedding run

Avoid for

  • Matching customer records or short field values, where data.detect_duplicates fits
  • Deciding which chunks are most relevant, which knowledge.rank_bm25 answers
  • Merging duplicates into a single combined chunk

Composable with

Safety & privacy

  • Runs without calling any external service.
  • Your payloads are never stored permanently.
  • Telemetry captures metadata only — never your payload contents.
  • We never train models on your payloads.
  • No human reviews your payloads.

Tags

textdeduplicationretrieval