Skip to content

from promplate.chain import *#

promplate.chain.callback #

BaseCallback #

Bases: Protocol

Source code in promplate/chain/callback.py
class BaseCallback(Protocol):
    def pre_process(self, context: "ChainContext") -> Context | Awaitable[Context | None] | None: ...

    def mid_process(self, context: "ChainContext") -> Context | Awaitable[Context | None] | None: ...

    def end_process(self, context: "ChainContext") -> Context | Awaitable[Context | None] | None: ...

    def on_enter(self, node: "Interruptible", context: Context | None, config: Context) -> tuple[Context | None, Context]:
        return context, config

    def on_leave(self, node: "Interruptible", context: "ChainContext", config: Context) -> tuple["ChainContext", Context]:
        return context, config

pre_process #

pre_process(context: ChainContext) -> Context | Awaitable[Context | None] | None
Source code in promplate/chain/callback.py
def pre_process(self, context: "ChainContext") -> Context | Awaitable[Context | None] | None: ...

mid_process #

mid_process(context: ChainContext) -> Context | Awaitable[Context | None] | None
Source code in promplate/chain/callback.py
def mid_process(self, context: "ChainContext") -> Context | Awaitable[Context | None] | None: ...

end_process #

end_process(context: ChainContext) -> Context | Awaitable[Context | None] | None
Source code in promplate/chain/callback.py
def end_process(self, context: "ChainContext") -> Context | Awaitable[Context | None] | None: ...

on_enter #

on_enter(node: Interruptible, context: Context | None, config: Context) -> tuple[Context | None, Context]
Source code in promplate/chain/callback.py
def on_enter(self, node: "Interruptible", context: Context | None, config: Context) -> tuple[Context | None, Context]:
    return context, config

on_leave #

on_leave(node: Interruptible, context: ChainContext, config: Context) -> tuple[ChainContext, Context]
Source code in promplate/chain/callback.py
def on_leave(self, node: "Interruptible", context: "ChainContext", config: Context) -> tuple["ChainContext", Context]:
    return context, config

Callback #

Bases: BaseCallback

Source code in promplate/chain/callback.py
class Callback(BaseCallback):
    def __init__(
        self,
        *,
        pre_process: "Process | AsyncProcess | None" = None,
        mid_process: "Process | AsyncProcess | None" = None,
        end_process: "Process | AsyncProcess | None" = None,
        on_enter: Callable[["Interruptible", Context | None, Context], tuple[Context | None, Context]] | None = None,
        on_leave: Callable[["Interruptible", "ChainContext", Context], tuple["ChainContext", Context]] | None = None,
    ):
        self._pre_process = pre_process
        self._mid_process = mid_process
        self._end_process = end_process
        self._on_enter = on_enter
        self._on_leave = on_leave

    def pre_process(self, context):
        if self._pre_process is not None:
            return self._pre_process(context)

    def mid_process(self, context):
        if self._mid_process is not None:
            return self._mid_process(context)

    def end_process(self, context):
        if self._end_process is not None:
            return self._end_process(context)

    def on_enter(self, node, context, config):
        if self._on_enter is not None:
            return self._on_enter(node, context, config)
        return context, config

    def on_leave(self, node, context, config):
        if self._on_leave is not None:
            return self._on_leave(node, context, config)
        return context, config

__init__ #

__init__(*, pre_process: Process | AsyncProcess | None = None, mid_process: Process | AsyncProcess | None = None, end_process: Process | AsyncProcess | None = None, on_enter: Callable[[Interruptible, Context | None, Context], tuple[Context | None, Context]] | None = None, on_leave: Callable[[Interruptible, ChainContext, Context], tuple[ChainContext, Context]] | None = None)
Source code in promplate/chain/callback.py
def __init__(
    self,
    *,
    pre_process: "Process | AsyncProcess | None" = None,
    mid_process: "Process | AsyncProcess | None" = None,
    end_process: "Process | AsyncProcess | None" = None,
    on_enter: Callable[["Interruptible", Context | None, Context], tuple[Context | None, Context]] | None = None,
    on_leave: Callable[["Interruptible", "ChainContext", Context], tuple["ChainContext", Context]] | None = None,
):
    self._pre_process = pre_process
    self._mid_process = mid_process
    self._end_process = end_process
    self._on_enter = on_enter
    self._on_leave = on_leave

pre_process #

pre_process(context)
Source code in promplate/chain/callback.py
def pre_process(self, context):
    if self._pre_process is not None:
        return self._pre_process(context)

mid_process #

mid_process(context)
Source code in promplate/chain/callback.py
def mid_process(self, context):
    if self._mid_process is not None:
        return self._mid_process(context)

end_process #

end_process(context)
Source code in promplate/chain/callback.py
def end_process(self, context):
    if self._end_process is not None:
        return self._end_process(context)

on_enter #

on_enter(node, context, config)
Source code in promplate/chain/callback.py
def on_enter(self, node, context, config):
    if self._on_enter is not None:
        return self._on_enter(node, context, config)
    return context, config

on_leave #

on_leave(node, context, config)
Source code in promplate/chain/callback.py
def on_leave(self, node, context, config):
    if self._on_leave is not None:
        return self._on_leave(node, context, config)
    return context, config

promplate.chain.node #

C module-attribute #

C = TypeVar('C', bound='ChainContext')

Process module-attribute #

Process = Callable[[ChainContext], Context | None]

AsyncProcess module-attribute #

AsyncProcess = Callable[[ChainContext], Awaitable[Context | None]]

Configurable #

Source code in promplate/llm/base.py
class Configurable:
    def __init__(self, **config):
        for key, val in config.items():
            setattr(self, key, val)

    @property
    def _config(self):
        return {k: v for k, v in self.__dict__.items() if not k.startswith("_")}

__init__ #

__init__(**config)
Source code in promplate/llm/base.py
6
7
8
def __init__(self, **config):
    for key, val in config.items():
        setattr(self, key, val)

Complete #

Bases: Protocol

Source code in promplate/llm/base.py
class Complete(Protocol):
    def __call__(self, prompt, /, **config) -> str: ...

__call__ #

__call__(prompt, /, **config) -> str
Source code in promplate/llm/base.py
def __call__(self, prompt, /, **config) -> str: ...

Generate #

Bases: Protocol

Source code in promplate/llm/base.py
class Generate(Protocol):
    def __call__(self, prompt, /, **config) -> Iterable[str]: ...

__call__ #

__call__(prompt, /, **config) -> Iterable[str]
Source code in promplate/llm/base.py
def __call__(self, prompt, /, **config) -> Iterable[str]: ...

AsyncComplete #

Bases: Protocol

Source code in promplate/llm/base.py
class AsyncComplete(Protocol):
    def __call__(self, prompt, /, **config) -> Awaitable[str]: ...

__call__ #

__call__(prompt, /, **config) -> Awaitable[str]
Source code in promplate/llm/base.py
def __call__(self, prompt, /, **config) -> Awaitable[str]: ...

AsyncGenerate #

Bases: Protocol

Source code in promplate/llm/base.py
class AsyncGenerate(Protocol):
    def __call__(self, prompt, /, **config) -> AsyncIterable[str]: ...

__call__ #

__call__(prompt, /, **config) -> AsyncIterable[str]
Source code in promplate/llm/base.py
def __call__(self, prompt, /, **config) -> AsyncIterable[str]: ...

LLM #

Bases: Protocol

Source code in promplate/llm/base.py
class LLM(Protocol):
    @partial(cast, Complete | AsyncComplete)
    def complete(self, prompt, /, **config) -> str | Awaitable[str]: ...

    @partial(cast, Generate | AsyncGenerate)
    def generate(self, prompt, /, **config) -> Iterable[str] | AsyncIterable[str]: ...

complete #

complete(prompt, /, **config) -> str | Awaitable[str]
Source code in promplate/llm/base.py
@partial(cast, Complete | AsyncComplete)
def complete(self, prompt, /, **config) -> str | Awaitable[str]: ...

generate #

generate(prompt, /, **config) -> Iterable[str] | AsyncIterable[str]
Source code in promplate/llm/base.py
@partial(cast, Generate | AsyncGenerate)
def generate(self, prompt, /, **config) -> Iterable[str] | AsyncIterable[str]: ...

ChainContext #

Bases: SafeChainMapContext

Source code in promplate/chain/node.py
class ChainContext(SafeChainMapContext):
    @overload
    def __new__(cls): ...

    @overload
    def __new__(cls, least: C, *maps: Mapping) -> C: ...

    @overload
    def __new__(cls, least: MutableMapping | None = None, *maps: Mapping): ...

    def __init__(self, least: MutableMapping | None = None, *maps: Mapping):
        super().__init__({} if least is None else least, *maps)  # type: ignore

    def __new__(cls, *args, **kwargs):  # type: ignore
        try:
            least = args[0]
        except IndexError:
            least = kwargs.get("least")
        if isinstance(least, cls) and least.__class__ is not cls:
            return least.__class__(*args, **kwargs)

        return super().__new__(cls, *args, **kwargs)

    @classmethod
    def ensure(cls, context):
        return context if isinstance(context, cls) else cls(context)

    @property
    def result(self):
        return self.__getitem__("__result__")

    @result.setter
    def result(self, result):
        self.__setitem__("__result__", result)

    @result.deleter
    def result(self):
        self.__delitem__("__result__")

    def __str__(self):
        return str({**self})

result deletable property writable #

result

__init__ #

__init__(least: MutableMapping | None = None, *maps: Mapping)
Source code in promplate/chain/node.py
def __init__(self, least: MutableMapping | None = None, *maps: Mapping):
    super().__init__({} if least is None else least, *maps)  # type: ignore

__new__ #

__new__()
__new__(least: C, *maps: Mapping) -> C
__new__(least: MutableMapping | None = None, *maps: Mapping)
__new__(*args, **kwargs)
Source code in promplate/chain/node.py
def __new__(cls, *args, **kwargs):  # type: ignore
    try:
        least = args[0]
    except IndexError:
        least = kwargs.get("least")
    if isinstance(least, cls) and least.__class__ is not cls:
        return least.__class__(*args, **kwargs)

    return super().__new__(cls, *args, **kwargs)

ensure classmethod #

ensure(context)
Source code in promplate/chain/node.py
@classmethod
def ensure(cls, context):
    return context if isinstance(context, cls) else cls(context)

__str__ #

__str__()
Source code in promplate/chain/node.py
def __str__(self):
    return str({**self})

AbstractNode #

Bases: Protocol

Source code in promplate/chain/node.py
class AbstractNode(Protocol):
    def invoke(
        self,
        context: Context | None = None,
        /,
        complete: Complete | None = None,
        **config,
    ) -> ChainContext: ...

    async def ainvoke(
        self,
        context: Context | None = None,
        /,
        complete: Complete | AsyncComplete | None = None,
        **config,
    ) -> ChainContext: ...

    def stream(
        self,
        context: Context | None = None,
        /,
        generate: Generate | None = None,
        **config,
    ) -> Iterable[ChainContext]: ...

    def astream(
        self,
        context: Context | None = None,
        /,
        generate: Generate | AsyncGenerate | None = None,
        **config,
    ) -> AsyncIterable[ChainContext]: ...

    @classmethod
    def _get_chain_type(cls):
        return Chain

    def __add__(self, chain: "AbstractNode"):
        if isinstance(chain, Chain):
            return self._get_chain_type()(self, *chain)
        return self._get_chain_type()(self, chain)

invoke #

invoke(context: Context | None = None, /, complete: Complete | None = None, **config) -> ChainContext
Source code in promplate/chain/node.py
def invoke(
    self,
    context: Context | None = None,
    /,
    complete: Complete | None = None,
    **config,
) -> ChainContext: ...

ainvoke async #

ainvoke(context: Context | None = None, /, complete: Complete | AsyncComplete | None = None, **config) -> ChainContext
Source code in promplate/chain/node.py
async def ainvoke(
    self,
    context: Context | None = None,
    /,
    complete: Complete | AsyncComplete | None = None,
    **config,
) -> ChainContext: ...

stream #

stream(context: Context | None = None, /, generate: Generate | None = None, **config) -> Iterable[ChainContext]
Source code in promplate/chain/node.py
def stream(
    self,
    context: Context | None = None,
    /,
    generate: Generate | None = None,
    **config,
) -> Iterable[ChainContext]: ...

astream #

astream(context: Context | None = None, /, generate: Generate | AsyncGenerate | None = None, **config) -> AsyncIterable[ChainContext]
Source code in promplate/chain/node.py
def astream(
    self,
    context: Context | None = None,
    /,
    generate: Generate | AsyncGenerate | None = None,
    **config,
) -> AsyncIterable[ChainContext]: ...

__add__ #

__add__(chain: AbstractNode)
Source code in promplate/chain/node.py
def __add__(self, chain: "AbstractNode"):
    if isinstance(chain, Chain):
        return self._get_chain_type()(self, *chain)
    return self._get_chain_type()(self, chain)

Interruptible #

Bases: AbstractNode, Protocol

Source code in promplate/chain/node.py
class Interruptible(AbstractNode, Protocol):
    def _invoke(
        self,
        context: ChainContext,
        /,
        complete: Complete | None,
        callbacks: list[BaseCallback],
        **config,
    ): ...

    async def _ainvoke(
        self,
        context: ChainContext,
        /,
        complete: Complete | AsyncComplete | None,
        callbacks: list[BaseCallback],
        **config,
    ): ...

    def _stream(
        self,
        context: ChainContext,
        /,
        generate: Generate | None,
        callbacks: list[BaseCallback],
        **config,
    ) -> Iterable: ...

    def _astream(
        self,
        context: ChainContext,
        /,
        generate: Generate | AsyncGenerate | None,
        callbacks: list[BaseCallback],
        **config,
    ) -> AsyncIterable: ...

    callbacks: list[BaseCallback | type[BaseCallback]]

    def enter(self, context: Context | None, config: Context):
        callbacks: list[BaseCallback] = ensure_callbacks(self.callbacks)
        for callback in callbacks:
            context, config = callback.on_enter(self, context, config)
        return context, config, callbacks

    def leave(self, context: ChainContext, config: Context, callbacks: list[BaseCallback]):
        for callback in reversed(callbacks):
            context, config = callback.on_leave(self, context, config)
        return context, config

    def add_pre_processes(self, *processes: Process | AsyncProcess):
        self.callbacks.extend(Callback(pre_process=i) for i in processes)
        return self

    def add_mid_processes(self, *processes: Process | AsyncProcess):
        self.callbacks.extend(Callback(mid_process=i) for i in processes)
        return self

    def add_end_processes(self, *processes: Process | AsyncProcess):
        self.callbacks.extend(Callback(end_process=i) for i in processes)
        return self

    def add_callbacks(self, *callbacks: BaseCallback | type[BaseCallback]):
        self.callbacks.extend(callbacks)
        return self

    def pre_process(self, process: Process | AsyncProcess):
        self.add_pre_processes(process)
        return process

    def mid_process(self, process: Process | AsyncProcess):
        self.add_mid_processes(process)
        return process

    def end_process(self, process: Process | AsyncProcess):
        self.add_end_processes(process)
        return process

    def callback(self, callback: BaseCallback | type[BaseCallback]):
        self.add_callbacks(callback)
        return callback

    @staticmethod
    def _apply_pre_processes(context: ChainContext, callbacks: list[BaseCallback]):
        for callback in callbacks:
            context |= cast(Context, callback.pre_process(context) or {})

    @staticmethod
    def _apply_mid_processes(context: ChainContext, callbacks: list[BaseCallback]):
        for callback in callbacks:
            context |= cast(Context, callback.mid_process(context) or {})

    @staticmethod
    def _apply_end_processes(context: ChainContext, callbacks: list[BaseCallback]):
        for callback in reversed(callbacks):
            context |= cast(Context, callback.end_process(context) or {})

    @staticmethod
    async def _apply_async_pre_processes(context: ChainContext, callbacks: list[BaseCallback]):
        for callback in callbacks:
            context |= cast(Context, await resolve(callback.pre_process(context)) or {})

    @staticmethod
    async def _apply_async_mid_processes(context: ChainContext, callbacks: list[BaseCallback]):
        for callback in callbacks:
            context |= cast(Context, await resolve(callback.mid_process(context)) or {})

    @staticmethod
    async def _apply_async_end_processes(context: ChainContext, callbacks: list[BaseCallback]):
        for callback in reversed(callbacks):
            context |= cast(Context, await resolve(callback.end_process(context)) or {})

    def invoke(self, context=None, /, complete=None, **config) -> ChainContext:
        context, config, callbacks = self.enter(context, config)
        context = ChainContext.ensure(context)

        try:
            self._invoke(ChainContext(context, self.context), complete, callbacks, **config)
        except Jump as jump:
            context, config = self.leave(context, config, callbacks)
            if jump.out_of is not None and jump.out_of is not self:
                raise jump from None
            if jump.into is not None:
                jump.into.invoke(context, complete, **config)
        else:
            context, config = self.leave(context, config, callbacks)

        return context

    async def ainvoke(self, context=None, /, complete=None, **config) -> ChainContext:
        context, config, callbacks = self.enter(context, config)
        context = ChainContext.ensure(context)

        try:
            await self._ainvoke(ChainContext(context, self.context), complete, callbacks, **config)
        except Jump as jump:
            context, config = self.leave(context, config, callbacks)
            if jump.out_of is not None and jump.out_of is not self:
                raise jump from None
            if jump.into is not None:
                await jump.into.ainvoke(context, complete, **config)
        else:
            context, config = self.leave(context, config, callbacks)

        return context

    def stream(self, context=None, /, generate=None, **config) -> Iterable[ChainContext]:
        context, config, callbacks = self.enter(context, config)
        context = ChainContext.ensure(context)

        try:
            for _ in self._stream(ChainContext(context, self.context), generate, callbacks, **config):
                yield context
        except Jump as jump:
            context, config = self.leave(context, config, callbacks)
            if jump.out_of is not None and jump.out_of is not self:
                raise jump from None
            if jump.into is not None:
                yield from jump.into.stream(context, generate, **config)
        else:
            context, config = self.leave(context, config, callbacks)

    async def astream(self, context=None, /, generate=None, **config) -> AsyncIterable[ChainContext]:
        context, config, callbacks = self.enter(context, config)
        context = ChainContext.ensure(context)

        try:
            async for _ in self._astream(ChainContext(context, self.context), generate, callbacks, **config):
                yield context
        except Jump as jump:
            context, config = self.leave(context, config, callbacks)
            if jump.out_of is not None and jump.out_of is not self:
                raise jump from None
            if jump.into is not None:
                async for i in jump.into.astream(context, generate, **config):
                    yield i
        else:
            context, config = self.leave(context, config, callbacks)

    _context: Context | None

    @property
    def context(self):
        if self._context is None:
            self._context = {}
        return self._context

    @context.setter
    def context(self, context: Context | None):
        self._context = context

    @context.deleter
    def context(self):
        self._context = None

callbacks instance-attribute #

context deletable property writable #

context

enter #

enter(context: Context | None, config: Context)
Source code in promplate/chain/node.py
def enter(self, context: Context | None, config: Context):
    callbacks: list[BaseCallback] = ensure_callbacks(self.callbacks)
    for callback in callbacks:
        context, config = callback.on_enter(self, context, config)
    return context, config, callbacks

leave #

leave(context: ChainContext, config: Context, callbacks: list[BaseCallback])
Source code in promplate/chain/node.py
def leave(self, context: ChainContext, config: Context, callbacks: list[BaseCallback]):
    for callback in reversed(callbacks):
        context, config = callback.on_leave(self, context, config)
    return context, config

add_pre_processes #

add_pre_processes(*processes: Process | AsyncProcess)
Source code in promplate/chain/node.py
def add_pre_processes(self, *processes: Process | AsyncProcess):
    self.callbacks.extend(Callback(pre_process=i) for i in processes)
    return self

add_mid_processes #

add_mid_processes(*processes: Process | AsyncProcess)
Source code in promplate/chain/node.py
def add_mid_processes(self, *processes: Process | AsyncProcess):
    self.callbacks.extend(Callback(mid_process=i) for i in processes)
    return self

add_end_processes #

add_end_processes(*processes: Process | AsyncProcess)
Source code in promplate/chain/node.py
def add_end_processes(self, *processes: Process | AsyncProcess):
    self.callbacks.extend(Callback(end_process=i) for i in processes)
    return self

add_callbacks #

add_callbacks(*callbacks: BaseCallback | type[BaseCallback])
Source code in promplate/chain/node.py
def add_callbacks(self, *callbacks: BaseCallback | type[BaseCallback]):
    self.callbacks.extend(callbacks)
    return self

pre_process #

pre_process(process: Process | AsyncProcess)
Source code in promplate/chain/node.py
def pre_process(self, process: Process | AsyncProcess):
    self.add_pre_processes(process)
    return process

mid_process #

mid_process(process: Process | AsyncProcess)
Source code in promplate/chain/node.py
def mid_process(self, process: Process | AsyncProcess):
    self.add_mid_processes(process)
    return process

end_process #

end_process(process: Process | AsyncProcess)
Source code in promplate/chain/node.py
def end_process(self, process: Process | AsyncProcess):
    self.add_end_processes(process)
    return process

callback #

callback(callback: BaseCallback | type[BaseCallback])
Source code in promplate/chain/node.py
def callback(self, callback: BaseCallback | type[BaseCallback]):
    self.add_callbacks(callback)
    return callback

invoke #

invoke(context=None, /, complete=None, **config) -> ChainContext
Source code in promplate/chain/node.py
def invoke(self, context=None, /, complete=None, **config) -> ChainContext:
    context, config, callbacks = self.enter(context, config)
    context = ChainContext.ensure(context)

    try:
        self._invoke(ChainContext(context, self.context), complete, callbacks, **config)
    except Jump as jump:
        context, config = self.leave(context, config, callbacks)
        if jump.out_of is not None and jump.out_of is not self:
            raise jump from None
        if jump.into is not None:
            jump.into.invoke(context, complete, **config)
    else:
        context, config = self.leave(context, config, callbacks)

    return context

ainvoke async #

ainvoke(context=None, /, complete=None, **config) -> ChainContext
Source code in promplate/chain/node.py
async def ainvoke(self, context=None, /, complete=None, **config) -> ChainContext:
    context, config, callbacks = self.enter(context, config)
    context = ChainContext.ensure(context)

    try:
        await self._ainvoke(ChainContext(context, self.context), complete, callbacks, **config)
    except Jump as jump:
        context, config = self.leave(context, config, callbacks)
        if jump.out_of is not None and jump.out_of is not self:
            raise jump from None
        if jump.into is not None:
            await jump.into.ainvoke(context, complete, **config)
    else:
        context, config = self.leave(context, config, callbacks)

    return context

stream #

stream(context=None, /, generate=None, **config) -> Iterable[ChainContext]
Source code in promplate/chain/node.py
def stream(self, context=None, /, generate=None, **config) -> Iterable[ChainContext]:
    context, config, callbacks = self.enter(context, config)
    context = ChainContext.ensure(context)

    try:
        for _ in self._stream(ChainContext(context, self.context), generate, callbacks, **config):
            yield context
    except Jump as jump:
        context, config = self.leave(context, config, callbacks)
        if jump.out_of is not None and jump.out_of is not self:
            raise jump from None
        if jump.into is not None:
            yield from jump.into.stream(context, generate, **config)
    else:
        context, config = self.leave(context, config, callbacks)

astream async #

astream(context=None, /, generate=None, **config) -> AsyncIterable[ChainContext]
Source code in promplate/chain/node.py
async def astream(self, context=None, /, generate=None, **config) -> AsyncIterable[ChainContext]:
    context, config, callbacks = self.enter(context, config)
    context = ChainContext.ensure(context)

    try:
        async for _ in self._astream(ChainContext(context, self.context), generate, callbacks, **config):
            yield context
    except Jump as jump:
        context, config = self.leave(context, config, callbacks)
        if jump.out_of is not None and jump.out_of is not self:
            raise jump from None
        if jump.into is not None:
            async for i in jump.into.astream(context, generate, **config):
                yield i
    else:
        context, config = self.leave(context, config, callbacks)

Interruptable #

Bases: Interruptible, Protocol

Source code in promplate/chain/node.py
@deprecated("Use `Interruptible` instead")
class Interruptable(Interruptible, Protocol): ...

Node #

Bases: Loader, Interruptible

Source code in promplate/chain/node.py
class Node(Loader, Interruptible):
    def __init__(
        self,
        template: Template | str,
        partial_context: Context | None = None,
        llm: LLM | None = None,
        **config,
    ):
        self.template = Template(template) if isinstance(template, str) else template
        self._context = partial_context
        self.callbacks: list[BaseCallback | type[BaseCallback]] = []
        self.llm = llm
        self.run_config = config

    def _invoke(self, context, /, complete, callbacks, **config):
        complete = cast(Complete, self.llm.complete if self.llm else complete)
        assert complete is not None

        prompt = self.render(context, callbacks)

        context.result = complete(prompt, **(self.run_config | config))

        self._apply_mid_processes(context, callbacks)

        self._apply_end_processes(context, callbacks)

    def _stream(self, context, /, generate, callbacks, **config):
        generate = cast(Generate, self.llm.generate if self.llm else generate)
        assert generate is not None

        prompt = self.render(context, callbacks)

        for result in accumulate(generate(prompt, **(self.run_config | config))):
            context.result = result
            self._apply_mid_processes(context, callbacks)
            yield

        self._apply_end_processes(context, callbacks)

    async def _ainvoke(self, context, /, complete, callbacks, **config):
        complete = cast(Complete | AsyncComplete, self.llm.complete if self.llm else complete)
        assert complete is not None

        prompt = await self.arender(context, callbacks)

        context.result = await resolve(complete(prompt, **(self.run_config | config)))

        await self._apply_async_mid_processes(context, callbacks)

        await self._apply_async_end_processes(context, callbacks)

    async def _astream(self, context, /, generate, callbacks, **config):
        generate = cast(Generate | AsyncGenerate, self.llm.generate if self.llm else generate)
        assert generate is not None

        prompt = await self.arender(context, callbacks)

        async for result in accumulate_any(generate(prompt, **(self.run_config | config))):
            context.result = result
            await self._apply_async_mid_processes(context, callbacks)
            yield

        await self._apply_async_end_processes(context, callbacks)

    def render(self, context: Context | None = None, callbacks: list[BaseCallback] | None = None):
        if callbacks is None:
            callbacks = ensure_callbacks(self.callbacks)
        context = ChainContext(context, self.context)
        self._apply_pre_processes(context, callbacks)
        return self.template.render(context)

    async def arender(self, context: Context | None = None, callbacks: list[BaseCallback] | None = None):
        if callbacks is None:
            callbacks = ensure_callbacks(self.callbacks)
        context = ChainContext(context, self.context)
        await self._apply_async_pre_processes(context, callbacks)
        return await self.template.arender(context)

    def __str__(self):
        return f"</{self.name}/>"

template instance-attribute #

template = Template(template) if isinstance(template, str) else template

callbacks instance-attribute #

callbacks: list[BaseCallback | type[BaseCallback]] = []

llm instance-attribute #

llm = llm

run_config instance-attribute #

run_config = config

__init__ #

__init__(template: Template | str, partial_context: Context | None = None, llm: LLM | None = None, **config)
Source code in promplate/chain/node.py
def __init__(
    self,
    template: Template | str,
    partial_context: Context | None = None,
    llm: LLM | None = None,
    **config,
):
    self.template = Template(template) if isinstance(template, str) else template
    self._context = partial_context
    self.callbacks: list[BaseCallback | type[BaseCallback]] = []
    self.llm = llm
    self.run_config = config

render #

render(context: Context | None = None, callbacks: list[BaseCallback] | None = None)
Source code in promplate/chain/node.py
def render(self, context: Context | None = None, callbacks: list[BaseCallback] | None = None):
    if callbacks is None:
        callbacks = ensure_callbacks(self.callbacks)
    context = ChainContext(context, self.context)
    self._apply_pre_processes(context, callbacks)
    return self.template.render(context)

arender async #

arender(context: Context | None = None, callbacks: list[BaseCallback] | None = None)
Source code in promplate/chain/node.py
async def arender(self, context: Context | None = None, callbacks: list[BaseCallback] | None = None):
    if callbacks is None:
        callbacks = ensure_callbacks(self.callbacks)
    context = ChainContext(context, self.context)
    await self._apply_async_pre_processes(context, callbacks)
    return await self.template.arender(context)

__str__ #

__str__()
Source code in promplate/chain/node.py
def __str__(self):
    return f"</{self.name}/>"

Loop #

Bases: Interruptible

Source code in promplate/chain/node.py
class Loop(Interruptible):
    def __init__(self, chain: AbstractNode, partial_context: Context | None = None):
        self.chain = chain
        self._context = partial_context
        self.callbacks: list[BaseCallback | type[BaseCallback]] = []

    def _invoke(self, context, /, complete, callbacks, **config):
        while True:
            self._apply_pre_processes(context, callbacks)
            self.chain.invoke(context, complete, **config)
            self._apply_mid_processes(context, callbacks)
            self._apply_end_processes(context, callbacks)

    async def _ainvoke(self, context, /, complete, callbacks, **config):
        while True:
            await self._apply_async_pre_processes(context, callbacks)
            await self.chain.ainvoke(context, complete, **config)
            await self._apply_async_mid_processes(context, callbacks)
            await self._apply_async_end_processes(context, callbacks)

    def _stream(self, context, /, generate, callbacks, **config):
        while True:
            self._apply_pre_processes(context, callbacks)
            for _ in self.chain.stream(context, generate, **config):
                self._apply_mid_processes(context, callbacks)
                yield
            self._apply_end_processes(context, callbacks)

    async def _astream(self, context, /, generate, callbacks, **config):
        while True:
            await self._apply_async_pre_processes(context, callbacks)
            async for _ in self.chain.astream(context, generate, **config):
                await self._apply_async_mid_processes(context, callbacks)
                yield
            await self._apply_async_end_processes(context, callbacks)

chain instance-attribute #

chain = chain

callbacks instance-attribute #

callbacks: list[BaseCallback | type[BaseCallback]] = []

__init__ #

__init__(chain: AbstractNode, partial_context: Context | None = None)
Source code in promplate/chain/node.py
def __init__(self, chain: AbstractNode, partial_context: Context | None = None):
    self.chain = chain
    self._context = partial_context
    self.callbacks: list[BaseCallback | type[BaseCallback]] = []

Chain #

Bases: Interruptible

Source code in promplate/chain/node.py
class Chain(Interruptible):
    def __init__(self, *nodes: AbstractNode, partial_context: Context | None = None):
        self.nodes = list(nodes)
        self._context = partial_context
        self.callbacks: list[BaseCallback | type[BaseCallback]] = []

    @classmethod
    def _get_chain_type(cls):
        return cls

    def __iadd__(self, chain: AbstractNode):
        self.nodes.append(chain)
        return self

    def __iter__(self):
        return iter(self.nodes)

    def _invoke(self, context, /, complete, callbacks: list[BaseCallback], **config):
        self._apply_pre_processes(context, callbacks)
        for node in self.nodes:
            node.invoke(context, complete, **config)
            self._apply_mid_processes(context, callbacks)
        self._apply_end_processes(context, callbacks)

    async def _ainvoke(self, context, /, complete, callbacks: list[BaseCallback], **config):
        await self._apply_async_pre_processes(context, callbacks)
        for node in self.nodes:
            await node.ainvoke(context, complete, **config)
            await self._apply_async_mid_processes(context, callbacks)
        await self._apply_async_end_processes(context, callbacks)

    def _stream(self, context, /, generate, callbacks: list[BaseCallback], **config):
        self._apply_pre_processes(context, callbacks)
        for node in self.nodes:
            for _ in node.stream(context, generate, **config):
                self._apply_mid_processes(context, callbacks)
                yield
        self._apply_end_processes(context, callbacks)

    async def _astream(self, context, /, generate, callbacks: list[BaseCallback], **config):
        await self._apply_async_pre_processes(context, callbacks)
        for node in self.nodes:
            async for _ in node.astream(context, generate, **config):
                await self._apply_async_mid_processes(context, callbacks)
                yield
        await self._apply_async_end_processes(context, callbacks)

    def __repr__(self):
        return " + ".join(map(str, self.nodes))

nodes instance-attribute #

nodes = list(nodes)

callbacks instance-attribute #

callbacks: list[BaseCallback | type[BaseCallback]] = []

__init__ #

__init__(*nodes: AbstractNode, partial_context: Context | None = None)
Source code in promplate/chain/node.py
def __init__(self, *nodes: AbstractNode, partial_context: Context | None = None):
    self.nodes = list(nodes)
    self._context = partial_context
    self.callbacks: list[BaseCallback | type[BaseCallback]] = []

__iadd__ #

__iadd__(chain: AbstractNode)
Source code in promplate/chain/node.py
def __iadd__(self, chain: AbstractNode):
    self.nodes.append(chain)
    return self

__iter__ #

__iter__()
Source code in promplate/chain/node.py
def __iter__(self):
    return iter(self.nodes)

__repr__ #

__repr__()
Source code in promplate/chain/node.py
def __repr__(self):
    return " + ".join(map(str, self.nodes))

Jump #

Bases: Exception

Source code in promplate/chain/node.py
class Jump(Exception):
    def __init__(self, into: Interruptible | None = None, out_of: Interruptible | None = None):
        self.into = into
        self.out_of = out_of

    def __str__(self):
        return f"{self.out_of} does not exist in the chain hierarchy"

into instance-attribute #

into = into

out_of instance-attribute #

out_of = out_of

__init__ #

__init__(into: Interruptible | None = None, out_of: Interruptible | None = None)
Source code in promplate/chain/node.py
def __init__(self, into: Interruptible | None = None, out_of: Interruptible | None = None):
    self.into = into
    self.out_of = out_of

__str__ #

__str__()
Source code in promplate/chain/node.py
def __str__(self):
    return f"{self.out_of} does not exist in the chain hierarchy"

ensure_callbacks #

ensure_callbacks(callbacks: list[BaseCallback | type[BaseCallback]]) -> list[BaseCallback]
Source code in promplate/chain/node.py
def ensure_callbacks(callbacks: list[BaseCallback | type[BaseCallback]]) -> list[BaseCallback]:
    return [i() if isinstance(i, type) else i for i in callbacks]

promplate.chain.utils #

T module-attribute #

T = TypeVar('T')

appender #

appender(to_append: list[T]) -> Callable[[T], T]
Source code in promplate/chain/utils.py
def appender(to_append: list[T]) -> Callable[[T], T]:
    def append_processor(func: T) -> T:
        to_append.append(func)

        return func

    return append_processor

is_positional_parameter #

is_positional_parameter(p: Parameter)
Source code in promplate/chain/utils.py
def is_positional_parameter(p: "Parameter"):
    from inspect import Parameter

    return p.kind is Parameter.POSITIONAL_OR_KEYWORD or p.kind is Parameter.KEYWORD_ONLY

count_position_parameters #

count_position_parameters(func)
Source code in promplate/chain/utils.py
def count_position_parameters(func):
    from inspect import signature

    return sum(map(is_positional_parameter, signature(func).parameters.values()))

resolve async #

resolve(maybe_awaitable: T | Awaitable[T]) -> T
Source code in promplate/chain/utils.py
async def resolve(maybe_awaitable: T | Awaitable[T], /) -> T:
    from inspect import isawaitable

    while isawaitable(maybe_awaitable):
        maybe_awaitable = await maybe_awaitable

    return maybe_awaitable

async_accumulate async #

async_accumulate(async_iterable: AsyncIterable[str])
Source code in promplate/chain/utils.py
async def async_accumulate(async_iterable: AsyncIterable[str]):
    result = ""
    async for delta in async_iterable:
        result += delta
        yield result

accumulate_any #

accumulate_any(any_iterable: Iterable[str] | AsyncIterable[str])
Source code in promplate/chain/utils.py
def accumulate_any(any_iterable: Iterable[str] | AsyncIterable[str]):
    if "__aiter__" in dir(any_iterable):
        return async_accumulate(any_iterable)  # type: ignore

    async def _():
        for i in accumulate(cast(Iterable[str], any_iterable)):
            yield i

    return _()