| 11694 | } |
| 11695 | |
| 11696 | bool stop_decode = false; |
| 11697 | for (int ti = 0; ti < ntok && completion < max_tokens; ti++) { |
| 11698 | if (job_cancelled(j)) { |
| 11699 | stop_decode = true; |
| 11700 | break; |
| 11701 | } |
| 11702 | token = toks[ti]; |
| 11703 | if (ds4_token_is_stop_for_think_mode(s->engine, |
| 11704 | token, |
| 11705 | j->req.think_mode)) { |
| 11706 | finish = "stop"; |
| 11707 | stop_decode = true; |
| 11708 | break; |
| 11709 | } |
| 11710 | |
| 11711 | size_t piece_len = 0; |
| 11712 | char *piece = ds4_token_text(s->engine, token, &piece_len); |
| 11713 | completion++; |
| 11714 | |
| 11715 | trace_piece(s, trace_id, piece, piece_len); |
| 11716 | buf_append(&text, piece, piece_len); |
| 11717 | thinking_state_feed(&thinking, piece, piece_len); |
| 11718 | if (j->req.kind == REQ_CHAT && j->req.has_tools) { |
| 11719 | dsml_decode_tracker_update(&dsml_tracker, text.ptr, text.len); |
| 11720 | } |
| 11721 | |
| 11722 | size_t stop_pos = 0, stop_len = 0; |
| 11723 | bool hit_stop = stop_list_find_from(&j->req.stops, text.ptr, |
| 11724 | stop_scan_from, |
| 11725 | &stop_pos, &stop_len); |
| 11726 | size_t stream_len = hit_stop ? |
| 11727 | stop_pos : stop_list_stream_safe_len(&j->req.stops, text.len); |
| 11728 | if (stream_len > text.len) stream_len = text.len; |
| 11729 | stream_len = utf8_stream_safe_len(text.ptr, plain_stream_pos, |
| 11730 | stream_len, hit_stop); |
| 11731 | if (!hit_stop && j->req.stops.max_len > 1) { |
| 11732 | const size_t hold = j->req.stops.max_len - 1; |
| 11733 | stop_scan_from = text.len > hold ? text.len - hold : 0; |
| 11734 | } |
| 11735 | |
| 11736 | if (j->req.stream && !structured_stream && stream_len > plain_stream_pos) { |
| 11737 | char *delta = xstrndup(text.ptr + plain_stream_pos, stream_len - plain_stream_pos); |
| 11738 | bool ok = sse_chunk(j->fd, &j->req, id, delta, NULL); |
| 11739 | free(delta); |
| 11740 | if (!ok) { |
| 11741 | job_mark_cancelled(j); |
| 11742 | finish = "error"; |
| 11743 | snprintf(err, sizeof(err), "client stream write failed"); |
| 11744 | free(piece); |
| 11745 | stop_decode = true; |
| 11746 | break; |
| 11747 | } |
| 11748 | plain_stream_pos = stream_len; |
| 11749 | } |
| 11750 | if (j->req.stream && j->req.api == API_ANTHROPIC && |
| 11751 | !anthropic_sse_stream_update(j->fd, s, &j->req, id, |
| 11752 | &anthropic_live, text.ptr, stream_len, |
| 11753 | false)) { |
nothing calls this directly
no test coverage detected