PPysolate SpineREAD THE CODE · UNDERSTAND THE SYSTEM
课程与章节
源码索引 / CURRENT IMPLEMENTATION

guest/prefix.py

75 行 · 点击行号可定位;函数链接随声明位置更新,不手填行号。

跳到函数 / 声明
"""Append-only source intake; only leading, complete, literal/input tool reads.

No eval/exec here. Final execution and Future ownership remain in the existing path.
"""
import ast
import json


class Prefix:
    def __init__(self, inputs, manifest, prepare):
        self.inputs = inputs
        self.manifest = manifest
        self.early_names = {spec["name"] for spec in manifest if spec["allow_early_read"]}
        self.prepare = prepare
        self.source = ""
        self.seen = 0
        self.ready = []
        self.claimed = 0

    def feed(self, chunk):
        self.source += chunk
        # A trailing partial line is not a complete received statement.
        complete = self.source[:self.source.rfind("\n") + 1]
        try:
            tree = ast.parse(complete, filename="<spine>")
        except SyntaxError:
            return  # Incomplete/invalid source is diagnosed at final compile.
        for index, statement in enumerate(tree.body):
            if not self.candidate(statement):
                break  # Never pass a branch, dependency, mutation, import, or other code.
            if index < self.seen:
                continue
            self.seen = index + 1
            call = statement.value
            try:
                args = {k.arg: self.argument(k.value) for k in call.keywords}
                request = json.dumps({"tool": call.func.id, "args": args})
            except Exception:
                continue  # Argument errors are still raised at the actual Python call.
            handle = self.prepare(request)
            if handle:
                self.ready.append((request, handle))

    def candidate(self, statement):
        if not (isinstance(statement, ast.Assign) and len(statement.targets) == 1
                and isinstance(statement.targets[0], ast.Name)
                and statement.targets[0].id != "inputs"
                and statement.targets[0].id not in self.early_names):
            return False
        call = statement.value
        return (isinstance(call, ast.Call) and isinstance(call.func, ast.Name)
                and call.func.id in self.early_names and not call.args
                and all(k.arg is not None and self.literal_or_input(k.value) for k in call.keywords))

    @staticmethod
    def literal_or_input(node):
        if isinstance(node, ast.Constant):
            return isinstance(node.value, (str, int, float, bool, type(None)))
        return (isinstance(node, ast.Subscript) and isinstance(node.value, ast.Name)
                and node.value.id == "inputs" and isinstance(node.slice, ast.Constant)
                and isinstance(node.slice.value, (str, int)))

    def argument(self, node):
        if isinstance(node, ast.Constant):
            return node.value
        return self.inputs[node.slice.value]

    def claim(self, request):
        # Leading calls execute in source order even if the full program is not optimized.
        # Match the actual request too; never search ahead or reuse a different read.
        if self.claimed < len(self.ready) and self.ready[self.claimed][0] == request:
            handle = self.ready[self.claimed][1]
            self.claimed += 1
            return handle
        return None