---
url: >-
  https://adk.nht.io/api/@nhtio/adk/batteries/llm/transformers_js/helpers/variables/looseKeyedToolCallParser.md
description: >-
  Parse the DEGENERATE keyed form a small instruct model emits when it ignores
  every structured tool-call grammar: the bare tool NAME on its own line, then
  one or more `argname: value` lines.
---

# Variable: looseKeyedToolCallParser

```ts
const looseKeyedToolCallParser: ToolCallParserFn;
```

Defined in: [src/batteries/llm/chat\_common/tool\_parsers.ts:815](https://github.com/NHTIO/ADK/blob/v1.20260713.1/src/src/batteries/llm/chat_common/tool_parsers.ts#L815)

Parse the DEGENERATE keyed form a small instruct model emits when it ignores every structured
tool-call grammar: the bare tool NAME on its own line, then one or more `argname: value` lines.

## Remarks

Observed verbatim from **Gemma-4 E2B on LiteRT-web** (raw-captured): asked to call an answer tool it
emits, with no `call:`/braces/brackets/JSON at all —

```
say_i_dont_know
reason: The documentation does not contain a definition for that.
```

No marker-anchored or pythonic/JSON parser claims this, so the "call" leaks into the visible answer as
prose AND the turn looks like a refusal (the tool the model meant to invoke never fires). A 2B can't
be reliably *instructed* into a format (changing the prompt's documented format did not change the
output), so the robust path is to parse the shape it actually produces.

WEAK SIGNAL, gated HARD (like [barePythonicToolCallParser](barePythonicToolCallParser.md)): it only claims when the FIRST
non-empty line is EXACTLY a real offered tool name (`ctx.toolNames`) and is followed by at least one
`key: value` line. That gate is what keeps it from misreading ordinary prose ("Note: …", a heading
with a colon). Single call only (the degenerate form has no list syntax); runs LAST in `'auto'`.
