diff --git a/DesignReferenceShonar.png b/DesignReferenceShonar.png new file mode 100644 index 0000000..19bba55 Binary files /dev/null and b/DesignReferenceShonar.png differ diff --git a/backend/shonar/services/ai/_llm.py b/backend/shonar/services/ai/_llm.py index 0757a82..c791a3d 100644 --- a/backend/shonar/services/ai/_llm.py +++ b/backend/shonar/services/ai/_llm.py @@ -100,9 +100,14 @@ class ContractProgress: self._key_score += grant self._earned += grant - def feed(self, prefix: str) -> int | None: - new = self._emit(_CONTRACT_FIRST_TOKEN) if self._reported == 0 else None - result: int | None = new + def feed(self, prefix: str) -> list[int]: + """Scan the new tail of the accumulated prefix; return every + newly earned pct in order (possibly empty).""" + emits: list[int] = [] + if self._reported == 0: + got = self._emit(_CONTRACT_FIRST_TOKEN) + if got is not None: + emits.append(got) text = prefix while self._pos < len(text): c = text[self._pos] @@ -129,8 +134,9 @@ class ContractProgress: _KEY_POINTS_BUDGET[self._cur_key]) self._done_keys.add(self._cur_key) self._cur_key = None - result = self._emit( - _CONTRACT_FIRST_TOKEN + self._earned) or result + got = self._emit(_CONTRACT_FIRST_TOKEN + self._earned) + if got is not None: + emits.append(got) self._at_key_slot = True elif self._depth == 2: # a closed array item (arrays hold strings) @@ -140,8 +146,9 @@ class ContractProgress: - _ARR_ITEM * (self._items_open - 1) self._award(min(_ARR_ITEM, max(0, remaining)), _KEY_POINTS_BUDGET[self._cur_key]) - result = self._emit( - _CONTRACT_FIRST_TOKEN + self._earned) or result + got = self._emit(_CONTRACT_FIRST_TOKEN + self._earned) + if got is not None: + emits.append(got) else: self._str_buf.append(c) continue @@ -153,8 +160,9 @@ class ContractProgress: if c == "[" and self._cur_key: self._items_open = 0 self._award(_ARR_OPEN, _KEY_POINTS_BUDGET[self._cur_key]) - result = self._emit( - _CONTRACT_FIRST_TOKEN + self._earned) or result + got = self._emit(_CONTRACT_FIRST_TOKEN + self._earned) + if got is not None: + emits.append(got) elif c in "}]": self._depth -= 1 if self._depth == 1: @@ -164,15 +172,18 @@ class ContractProgress: _KEY_POINTS_BUDGET[self._cur_key]) self._done_keys.add(self._cur_key) self._cur_key = None - result = self._emit( - _CONTRACT_FIRST_TOKEN + self._earned) or result + got = self._emit(_CONTRACT_FIRST_TOKEN + self._earned) + if got is not None: + emits.append(got) self._at_key_slot = True elif self._depth == 0: self._root_closed = True - result = self._emit(_CONTRACT_ROOT) or result + got = self._emit(_CONTRACT_ROOT) + if got is not None: + emits.append(got) elif c == "," and self._depth == 1: self._at_key_slot = True - return result + return emits def make_progress_ticker(on_progress): @@ -188,10 +199,10 @@ def make_progress_ticker(on_progress): def feed(prefix: str) -> None: try: # noqa: SIM105 — swallow deliberately: progress is display state - pct = tracker.feed(prefix or "") + pcts = tracker.feed(prefix or "") except Exception: # display state only return - if pct is not None: + for pct in pcts: on_progress(pct) return feed