tags as $tag) { $this->results[$tag] = null; } } public function append(string $chunk): self { $this->chunk = $chunk; $this->buffer .= $chunk; return $this; } public function parse(): self { if ($this->buffer === '') { return $this; } foreach ($this->tags as $tag) { $positions = $this->positions($this->buffer, $tag); if (count($positions) >= 1) { $length = strlen('<|' . $this->name . $tag . '|>'); $content = substr($this->buffer, $positions[0] + $length, ($positions[1] ?? null) - $positions[0] - $length); $this->results[$tag] = $content; } else { $this->results[$tag] = null; } } return $this; } private function positions(string $buffer, string $tag): array { $pattern = "/<\\|" . $this->name . $tag . "\\|>/"; $matches = []; preg_match_all($pattern, $buffer, $matches, PREG_OFFSET_CAPTURE); return !empty($matches[0]) ? array_column($matches[0], 1) : []; } public function all(): array { return $this->results; } public function toArray(): array { return ['think' => $this->think, 'content' => $this->content, 'fields' => $this->fields, 'status' => $this->getStatus()]; } private function getStatus(): ?Status { if ($this->think && !$this->content) { return Status::Thinking; } if ($this->content) { return Status::Typing; } return null; } public function __get(string $tag) { if($tag === 'status') { return $this->getStatus(); } $string = $this->results[$tag] ?? null; if ($tag === 'fields') { try { return json_decode($string, true); } catch (\Throwable) { return []; } } return $string; } }