furb 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
furb/CLAUDE.md ADDED
@@ -0,0 +1,108 @@
1
+ ## Technical names
2
+
3
+ Each name has one meaning, which the contract's sentences use as given here.
4
+
5
+ - engine: the program in engine.py, which is the whole system prompt of a model.
6
+ - operator: the person or program that calls the engine from outside a rung.
7
+ - model: a language model that answers with python code.
8
+ - provider: the service that runs a model.
9
+ - actor: the operator, or a model at an effort, named model/effort; it answers prompts and makes acts.
10
+ - effort: one of the levels of reasoning the World offers, ordered from least to most.
11
+ - roster: the actors the World offers, each as its name, its efforts and its window.
12
+ - window: the context size of a model in tokens, as its roster entry says.
13
+ - share: the part of a window that one model response used.
14
+ - standing: what a chain stands on, which the World answers it: the roster, the directory and the default actor.
15
+ - default actor: the actor a prompt goes to when the prompt leaves the actor unsaid, bound as `actor` in the chain.
16
+ - World: the interface to the disk, the machine, the actors and the record; it keeps what the journal says it keeps,
17
+ and does what it hears it is started to do.
18
+ - Kernel: the interface that gates and runs rungs, and what it gates with is its own.
19
+ - boot: the life, given the record and the generators of the outside, which gives the root.
20
+ - bus: the three entries every verb speaks through: send for a fact, ask for a query, act for an act.
21
+ - fact: what is said to the life, inert, with no response, and queried later; a tuple of its kind, the act it is
22
+ about, who said it, and its words.
23
+ - kind: the first slot of a fact; for a question, the verb that made it.
24
+ - question: a fact that is asked; it takes a name when it is said, its first word is the chain it is on, and what
25
+ it was answered the life holds under its name; an act if it lives, a query if it does not.
26
+ - query: a synchronous question, answered now or with nothing.
27
+ - act: an asynchronous question, answered now or later, which a life lives, opened by the call and done by its done.
28
+ - life: the generator of an act, given its name, which hears every fact and speaks by yielding one; a verb makes it
29
+ with pausing, ending and started.
30
+ - outcome: what a question came to, held under its name once its done lands: the value or the exception.
31
+ - id: the name of a question, as a string, kind://lineage.n: its kind, the lineage of its maker, and its number
32
+ among that maker's.
33
+ - maker: the one whose lineage the name of an act hangs off.
34
+ - lineage: the makers of an act, one under the other, which its name holds after its kind; chains form a tree by
35
+ name, from the operator through their makers.
36
+ - under: what an act is to its ancestors.
37
+ - scope: the chain an act is on, and itself for a chain.
38
+ - root: chain://operator.1, which boot opens.
39
+ - chain: an act, chain://lineage.n, that holds the facts on it, with a module and a working directory of its own; with
40
+ a source it holds, besides, the acts it inherited.
41
+ - source: the chain a new chain retells, by its id, which means the transcript of that chain as it stands with the
42
+ filter applied.
43
+ - filter: a callable that says which acts of the transcript up to the source the turns of the new chain keep; take
44
+ makes the filter of the file.
45
+ - transcript: the facts a chain holds, in the order it heard them.
46
+ - turn: one item of what a model reads of a transcript, folded from the tells: a role, a content, a usage and blocks.
47
+ - known: a line that a model was told, in the transcript of its chain.
48
+ - prompt: the act that sends a message to an actor and wants a response of a shape.
49
+ - message: the text a prompt carries.
50
+ - shape: the python type of a response, which a prompt carries by its name.
51
+ - response: what a prompt completes with.
52
+ - acknowledgment: the prompt of nothing a chain makes when an act a rung made is done and no ask has shown it.
53
+ - rung: the run of one word on a chain, and the verb that runs a word its caller wrote.
54
+ - step: one turn of a model and the run of its word, which is one rung.
55
+ - ladder: the rungs of a chain in record order.
56
+ - program: the words the rungs of a chain accepted, the model's and its caller's alike, in the order of acceptance.
57
+ - globals: python's globals, the dict a rung runs in, which is the engine's module copied for the chain.
58
+ - gate: what the Kernel reads a word against before it runs: the rungs of its chain before it and the shape it must
59
+ give.
60
+ - command: what bash runs on the machine.
61
+ - merged: the state of a command whose stderr flows into its stdout, in the order the command wrote them.
62
+ - door: the name of an act, with a part after it or without; the word of a rung adds a door by making an act whose
63
+ life answers reads of a scheme, and the World serves the rest.
64
+ - text: what read gives, and what write is given and gives back as it landed; a Text, with a path and a content.
65
+ - show: a callable given the lines of a text, which gives the numbers of the lines the engine tells; span, grep and
66
+ differs make the shows of the file.
67
+ - template: a python template string, each interpolation of which carries an expression and its value.
68
+ - debug: the verb that tells the interpolations of a template, a tell and no act.
69
+ - control: a pause, a wake, a cancel or a close; a close is a cancel with a value, and a cancel a close with
70
+ CancelledError.
71
+ - paused: the state of an act while a pause over it stands with no wake after it.
72
+ - grant: an act that puts a ceiling on a chain: dollars, a share of the window, or both.
73
+ - ledger: what the grant holds: the dollars of the answers since it was made and the share the last one filled.
74
+ - record: the entries the journal keeps, in the order they were said.
75
+ - entry: one line of the record: the act made last before its fact, and the fact; for a query of a run, its answer
76
+ beside.
77
+ - drift: an act that, made again, does not agree with the record.
78
+
79
+ ## Laws no test holds
80
+
81
+ A model does everything with the python that the model writes.
82
+ The engine hosts itself.
83
+ The system prompt a model reads is the engine, minified in layout alone, and nothing else.
84
+ The engine phrases everything else that a model reads, and the World renders any tag.
85
+ Everything that the file defines is public, and what is in engine.py is the API, the same for the model and for the operator.
86
+ The defaults of every verb are public names in the file.
87
+ A model knows from the source alone what the engine does with what the model writes.
88
+ What the engine does to the word of a rung it does to itself.
89
+ The prompt is the one channel of the engine: every exchange between the operator, the models and a chain is a prompt.
90
+ A model extends the engine from a step: an extension writes verbs and lives, shows and filters as callables, and rebinds names, and it tells tags of its own, from a door or from a rebound verb.
91
+ The engine has no registry, no plugin surface, no permission and no REPL: the record says who made each act.
92
+ Within a chain, a rung binds, passes and returns any python value, plain or not.
93
+ When its share of the window is high, a model opens a chain with a source and a take that is not inside.
94
+ Compaction is not in the core.
95
+ engine.pyi is the specification of engine.py: it says what the engine is, what is always true of it and what its surface is, and never how it is made; it names the interfaces and the facts as python reads them, and holds every law, so engine.py holds no sentence and no comment.
96
+ engine.py depends only on the python interpreter and on the two interfaces the contract names, World and Kernel, which are generators given to boot, held by no verb and bound to no name of the engine.
97
+ A fact is a tuple, its kind first, deconstructed only by match, and nothing of the engine is a class but a text, an exit, the name of an act, and the two exceptions.
98
+ The verbs and Text carry their signatures, typed, since a model reads them; nothing else in engine.py has a type annotation but what ty and a dataclass need.
99
+ engine.py has no private names, and a name one thing alone uses lives inside it.
100
+ Each technical name has one meaning.
101
+ ty check passes on engine.py.
102
+ There is one root per record, and one process at a time owns a record.
103
+ A chain is a function of the record, and a later boot must offer the same interpreter and the same outside, since a record is made again by running its words.
104
+ A chain is one conversation, and the transcript that a provider caches grows at one end.
105
+ Nothing is told twice, and nothing tells what it does not know: an act tells of itself, and a chain of the rungs it asks for and of the words it refuses.
106
+ A drift is a hard error.
107
+ The engine owns the order of every run, and nothing of a model runs on the loop of the outside.
108
+ A chain with a source still asks its origin for its transcript, where the record is what a later life should make it from.
furb/__init__.py ADDED
File without changes
furb/cli.py ADDED
@@ -0,0 +1,111 @@
1
+ """The command line of furb: the door of the operator onto the root chain of one life.
2
+
3
+ One command is one life. The life is opened on a loop of its own, from the record it is given, and the operator
4
+ waits on that loop for what it asked. A prompt the record already holds is taken up again and never asked twice,
5
+ so a command said again on a kept record reads the answer of the life before it and asks no model for it.
6
+ """
7
+
8
+ import argparse
9
+ import asyncio
10
+ import sys
11
+ from collections.abc import Sequence
12
+ from pathlib import Path
13
+
14
+ from furb import engine
15
+ from furb.engine import Act
16
+ from furb.kernel import Native
17
+ from furb.provider.claude import ACTOR, cool
18
+ from furb.world import Live, kept, rendered
19
+
20
+ SHAPES: dict[str, type | None] = {"none": None, "str": str, "int": int, "float": float, "bool": bool, "list": list}
21
+ """SHAPES is every shape a prompt of the command line takes, by the name it is given on the line."""
22
+
23
+
24
+ def say(text: str) -> None:
25
+ """One line to the operator, said as it happens, since a line of a long run that waits for the end says nothing."""
26
+ sys.stdout.write(f"{text}\n")
27
+ sys.stdout.flush()
28
+
29
+
30
+ def lived(record: Path | None, cwd: Path, actor: str) -> tuple[Live, str, list[tuple]]:
31
+ """One life on the loop that runs: its World on the record, the Kernel of this interpreter, and its root."""
32
+ held = kept(record) if record is not None and record.is_file() else []
33
+ world = Live(str(cwd.absolute()), record, actor)
34
+ root = engine.boot(held, world=world.hears(), kernel=Native().kernel())
35
+ return world, root, held
36
+
37
+
38
+ def again(held: Sequence[tuple], root: str, shape: type | None, message: str, to: str) -> str:
39
+ """The name of the prompt the record already holds for this message, and nothing when it holds none.
40
+
41
+ The engine matches nothing the operator says again, so a life stood up on its own record would open a second
42
+ prompt beside the one that record stands on, and ask a model for what it was answered once.
43
+ """
44
+ named = shape.__name__ if isinstance(shape, type) else repr(shape)
45
+ for entry in held:
46
+ match entry:
47
+ case (_, ("prompt", id, "operator", on, kind, said, who)) if (on, kind, said, who) == (root, named, message, to):
48
+ return id
49
+ return ""
50
+
51
+
52
+ async def prompted(record: Path | None, cwd: Path, shape: type | None, message: str, to: str) -> object:
53
+ """One prompt of the operator on the root of a life, awaited for the shape it asks for."""
54
+ _, root, held = lived(record, cwd, ACTOR)
55
+ try:
56
+ if name := again(held, root, shape, message, to):
57
+ return await Act(name)
58
+ return await engine.prompt(shape, message, to, on=root)
59
+ finally:
60
+ # Nothing the life warmed outlives the life, so every process of the provider dies with the command.
61
+ await cool()
62
+
63
+
64
+ async def turned(record: Path, cwd: Path) -> None:
65
+ """The turns of the root of a life made again from its record, each as the text a model reads of it."""
66
+ root = lived(record, cwd, ACTOR)[1]
67
+ try:
68
+ for role, content, _, _ in engine.turns(on=root):
69
+ say(f"[{role}] {rendered(content)}")
70
+ finally:
71
+ await cool()
72
+
73
+
74
+ async def running(record: Path | None, cwd: Path, word: str) -> object:
75
+ """One word its caller wrote, run as a rung on the root of a life, awaited for what the word gave."""
76
+ root = lived(record, cwd, ACTOR)[1]
77
+ try:
78
+ return await engine.rung(word, on=root)
79
+ finally:
80
+ await cool()
81
+
82
+
83
+ def parser() -> argparse.ArgumentParser:
84
+ """What the command line takes: a prompt, the turns of a record, and a word the caller wrote."""
85
+ whole = argparse.ArgumentParser(prog="furb", description="The core of an AI harness.")
86
+ verbs = whole.add_subparsers(dest="verb", required=True)
87
+ one = verbs.add_parser("prompt", help="Prompt an actor on the root chain and print what the prompt gave.")
88
+ one.add_argument("message", help="What the actor is told.")
89
+ one.add_argument("--to", default="", help="The actor, as model/effort; the default actor of the chain when unsaid.")
90
+ one.add_argument("--shape", default="none", choices=sorted(SHAPES), help="The shape of the response.")
91
+ one.add_argument("--record", type=Path, default=None, help="The record to keep, and to resume from.")
92
+ one.add_argument("--cwd", type=Path, default=Path(), help="The directory the chains of the life start in.")
93
+ two = verbs.add_parser("turns", help="Print the turns of the root of a life made again from its record.")
94
+ two.add_argument("--record", type=Path, required=True, help="The record to resume from.")
95
+ two.add_argument("--cwd", type=Path, default=Path(), help="The directory the chains of the life start in.")
96
+ three = verbs.add_parser("run", help="Run a word the caller wrote on the root chain and print what it gave.")
97
+ three.add_argument("word", help="The python of the word.")
98
+ three.add_argument("--record", type=Path, default=None, help="The record to keep, and to resume from.")
99
+ three.add_argument("--cwd", type=Path, default=Path(), help="The directory the chains of the life start in.")
100
+ return whole
101
+
102
+
103
+ def main() -> None:
104
+ """The console script: one command of the operator, on one life, on a loop of its own."""
105
+ args = parser().parse_args()
106
+ if args.verb == "prompt":
107
+ say(repr(asyncio.run(prompted(args.record, args.cwd, SHAPES[args.shape], args.message, args.to))))
108
+ elif args.verb == "turns":
109
+ asyncio.run(turned(args.record, args.cwd))
110
+ else:
111
+ say(repr(asyncio.run(running(args.record, args.cwd, args.word))))