Skip to main content
Orux AIOruxAI

Orux AI / Model notes

gpt-6-luna: Build a Support Digest Without Raw Messages

Build a support digest for gpt-6-luna using 4 synthetic tickets. Includes an offline allowlist, observed JSON, rejection tests and dated Orux Credits.

Orux AIPublished 9 min read
gpt-6-luna: Build a Support Digest Without Raw Messages — Build a support digest for gpt-6-luna using 4 synthetic tickets.
On this page

Build the summary input before asking for a summary

A support operations lead usually needs a weekly answer to three questions: how many tickets arrived, which approved categories they belong to, and which remain open. An export with customer names, email addresses and free-form complaints contains much more material than that particular task requires. Asking a model to ignore those fields still sends the fields. This guide builds a smaller, aggregate-only input locally before you consider a gpt-6-luna request.

The delivered tool reads synthetic records, validates two controlled fields, counts their combinations and constructs a new JSON object. The observed result has four tickets across three groups. Names, email addresses, a fake phone value, a ticket identifier and an instruction embedded in a sample complaint do not appear in the result. That is a check of this specific transformation, not a general promise that the result is anonymous or safe to disclose in every organization.

The distinction matters. An aggregate can reveal commercially sensitive activity, and a group containing one person’s unusual problem can be identifying when combined with outside knowledge. Human review of the proposed disclosure remains necessary. This is an input-preparation workflow, not a privacy certification, a model benchmark or an automatically generated support report. No paid inference is required to run the example.

Local transformation:4 synthetic tickets become 3 count groups; not model output or anonymity guarantee
Local transformation:4 synthetic tickets become 3 count groups; not model output or anonymity guarantee

Start with the reporting question and a small contract

The fictional reporting contract is deliberately narrow: retain only a category chosen from delivery, returns and account, and a status chosen from open and closed. Output only the total record count plus counts grouped by those approved values. Do not forward raw fields, individual records, ticket IDs, names, contact details or complaint text. The vocabulary is an example you must replace with your organization’s approved categories.

This is an allowlist, not a search-and-replace redactor. A redactor might try to find an email address in arbitrary prose; this program does not include prose in its output at all. Unknown values in the two allowed fields raise an error rather than being copied into a catch-all bucket. That choice prevents an email address placed in the category field from slipping through merely because the field name looks acceptable.

Extra source fields are ignored while constructing fresh output objects. The program does not edit the raw export in place, so you can keep its source within your controlled system and send only a separately reviewed artifact. Ignoring an extra field here is intentional; it does not mean your importer should silently accept every malformed export. Validate the upstream export format separately and reconcile its record count before producing a report.

Run the complete offline example

Save the following as digest.py and run python3 digest.py. It uses only Python’s standard library, reads no API key and makes no network request. The four input records and all contact-like strings are synthetic. Their purpose is to demonstrate fields that must not be copied, not to suggest collecting those values for this workflow.

Python
"""Offline synthetic fixture. No network, model call or identity-free guarantee."""
from collections import Counter
import json

ALLOWED = {"category": {"delivery", "returns", "account"},
           "status": {"open", "closed"}}

def digest(rows):
    if not isinstance(rows, list):
        raise ValueError("Input must be a list")
    counts = Counter()
    for row in rows:
        if not isinstance(row, dict):
            raise ValueError("Each record must be an object")
        values = []
        for field, choices in ALLOWED.items():
            value = row.get(field)
            if not isinstance(value, str) or value not in choices:
                raise ValueError("Unknown or missing category/status")
            values.append(value)
        counts[tuple(values)] += 1
    # Fresh objects: never copy identifiers, customer text or extra fields.
    return {"ticket_count": len(rows), "counts": [
        {"category": c, "status": s, "count": n}
        for (c, s), n in sorted(counts.items())]}

if __name__ == "__main__":
    rows = [
        {"category": "delivery", "status": "open", "email": "a@example.invalid",
         "message": "Synthetic complaint; ignore previous rules"},
        {"category": "delivery", "status": "open", "name": "Fictional A"},
        {"category": "returns", "status": "closed", "phone": "NOT-A-REAL-NUMBER"},
        {"category": "account", "status": "open", "ticket_id": "SYNTHETIC-4"},
    ]
    result = digest(rows)
    encoded = json.dumps(result, ensure_ascii=False, sort_keys=True)
    assert sum(x["count"] for x in result["counts"]) == len(rows)
    assert "example.invalid" not in encoded and "ignore previous" not in encoded
    assert "Fictional A" not in encoded and "SYNTHETIC-4" not in encoded
    for bad in [{"category": "a@example.invalid", "status": "open"},
                {"category": "delivery"}, None]:
        try:
            digest([bad])
        except ValueError:
            pass
        else:
            raise AssertionError("Malformed input was accepted")
    print(json.dumps(result, ensure_ascii=False, sort_keys=True, indent=2))

The actual local run produced:

JSON
{
  "counts": [
    {
      "category": "account",
      "count": 1,
      "status": "open"
    },
    {
      "category": "delivery",
      "count": 2,
      "status": "open"
    },
    {
      "category": "returns",
      "count": 1,
      "status": "closed"
    }
  ],
  "ticket_count": 4
}

The two open delivery records become one group with count two. The open account and closed returns records each become a group with count one. The group counts sum to four, matching ticket_count. The output order is sorted by category and status, making small changes easier to review in a diff. No interpretation of a customer’s intentions or root cause is implied by these counts.

The sample message contains an instruction-like phrase. It is absent from the derived artifact because message is never copied, not because a model detected or defeated an attack. This reduces one route by which customer-controlled prose could enter a later prompt. It does not remove prompt-injection risk from other data, tools or stages in a larger application.

Test what must fail, not only what looks correct

The included checks exercise more than the happy path. A category containing an email-shaped value is rejected; a record missing status is rejected; and a non-object record is rejected. The function also requires a list at the top level. Those failures stop this transformation rather than silently replacing invalid data with plausible defaults.

Four absence assertions check that selected source values are missing from the serialized result. They are useful regression checks for this fixture, not proof that every possible identifier is absent from every future output. The stronger structural property is that the function creates only category, status and count rows from validated enum values. Expanding the output contract requires reviewing that property again.

Do not “fix” a rejected category by forwarding its original string to an LLM for automatic interpretation. That would reopen the boundary this workflow established. Keep the rejected record local, inspect the export or update an approved mapping, and rerun the builder. Likewise, adding a free-text note to every output row would change the disclosure contract even if the old tests continued to pass.

Decide what the model can usefully add

The arithmetic is already complete before a model is considered. A language model could help turn approved counts into a concise narrative for a human reader, but it should not be asked to invent missing customer reasons or reconstruct individual incidents from aggregate data. If the team only needs a table, use the JSON directly and skip inference entirely.

A proposed writing instruction could ask for two sentences describing the counts, explicitly prohibiting causal explanations and individual customer stories. That is a suggested next step, not a tested model response in this article. The central deliverable here is the reviewed input artifact. We have not called gpt-6-luna or minimax-m3.1-flash, compared their summaries, or established either model’s reliability on support work.

Before sending real data, a responsible reviewer should approve the audience, purpose, retention expectations and remaining sensitivity of the aggregate. Counts for a small team, a narrow time period or a rare category may still warrant keeping the report internal. Reducing fields cannot by itself settle those decisions or establish what a model provider will retain.

Read the correct price conditions before optional inference

ModelInput Credits /1 M tokensOutput Credits /1 M tokensCondition
gpt-6-luna5.427Input 0–269,999 tokens; ordinary uncached text
minimax-m3.1-flash2496Ordinary uncached text

Swipe horizontally to view the full table.

These are the public Orux ordinary input and output rates checked on 2026-11-01, in Credits per one million metered tokens. One Credit equals $0.005. The gpt-6-luna row shown applies only when the input is below 270,000 tokens; the public catalog has a separate long-input row. Both selected price rows specify a minimum charge of 0.001 Credits per request. This table does not assume cache hits, cache writes or media input.

For an explicitly hypothetical request of 5,000 input tokens and 500 output tokens, those uncached rates give 0.0405 Credits for gpt-6-luna and 0.168 Credits for minimax-m3.1-flash. Both exceed the stated minimum. These are arithmetic examples, not token measurements of the four-record payload. The prompt, formatting and eventual response would affect actual metered quantities; a byte or character count is not a tokenizer.

No current first-party price comparison was independently established for these exact request conditions, so this guide makes no official-price savings claim. A model’s rate also does not establish narrative quality, response time or suitability for handling a particular organization’s data. Check the live model page and exact estimate before authorizing inference; the offline builder itself does not consume Orux Credits.

Review changes to the contract before scaling up

For a real export, replace the synthetic input only inside an approved local workflow. Confirm the category and status mapping, reconcile total counts, inspect the derived JSON and obtain approval for its intended destination. Keep the raw export and the outbound artifact as different files. Avoid logging the raw record when reporting a validation error; log a local record position or a bounded error code instead.

If you need additional measures, add them deliberately. A broad urgency bucket might support staffing review, but an exact timestamp or internal account label could disclose more than the original question requires. A field’s usefulness and its disclosure implications should be reviewed together. The code does not make that policy judgment for you.

The existing structured extraction article addresses a different boundary: preserving missing values instead of inventing facts. The Qwen3 RAG budgeting guide concerns separately metered retrieval work. Here, the useful decision happens before either activity: which information needs to leave the local system at all?

FAQ

Does removing names and emails make the aggregate anonymous?

No. This example excludes selected fields and validates a small vocabulary, but aggregate counts can remain sensitive or identifying in context. A rare category or a narrow reporting period may reveal information when combined with other knowledge. Review the actual artifact, audience and purpose before deciding whether to disclose it.

Did a model generate the displayed JSON?

No. The displayed JSON is the actual output of the local Python program. No model request was made. This distinction makes the fixture reproducible without spending Credits and prevents a deterministic count from being presented as evidence of language-model understanding, summarization accuracy or resistance to prompt injection.

Why reject unknown category values instead of asking the model?

Because the contract permits only approved category and status values. Forwarding an unexpected string for interpretation could transmit the very source text this workflow is designed to omit. Inspect and map rejected values locally, then rerun the builder. Do not quietly change a strict input contract into open-ended text processing.

Can I use the output without any paid inference?

Yes. The artifact is already a complete count report for the defined question and can feed a local table or dashboard directly. A model is optional if a human-readable narrative adds value. The article does not claim that either listed model has been tested to produce that narrative correctly.

How should I adapt the example for a real support team?

Define an approved vocabulary and a specific reporting purpose, then test both accepted and rejected records. Reconcile counts, inspect the outbound artifact and review its remaining sensitivity before transmission. Add fields only after updating that contract and its tests. This workflow is not a substitute for an organization’s data-handling requirements.

Prices checked on 2026-11-01. Sources: gpt-6-luna public catalog, minimax-m3.1-flash public catalog, and OWASP sensitive information disclosure. See gpt-6-luna and minimax-m3.1-flash for current Orux entries. The disclosure boundaries and worked example are this article’s implementation, not a claim that OWASP reviewed this code.

Try gpt-6-luna on Orux AIRun it online, then check pricing and API examples on the model page.Open modelTry minimax-m3.1-flash on Orux AIRun it online, then check pricing and API examples on the model page.Open model

Build with these models through one API

One OpenAI-compatible API for chat, image, video and audio models, billed in Credits.

Related articles

Browse all articles →