rama

The /learn commands in the ramabana terminal agent: the same tutor, in the terminal, next to your code.

This module is a ramabana extension. It gives the /learn commands in the terminal, and it uses the same Tutor and Session as the web app. It also gives two tools, so the coding agent can add concepts to the graph while you code.

These are the imports of the module.

Turn it on

A ramabana extension is a file in ~/.config/ramabana/extensions/ with a setup(reg) function. To turn on this extension, do these steps:

  1. Install abhyasa in the environment where ramabana runs.
  2. Make the file ~/.config/ramabana/extensions/abhyasa.py.
  3. Put this one line in the file: from abhyasa.rama import setup.
command what it does
/learn [topic or slug] start a session; name a concept to learn only that concept
/a <answer> answer; put the think-aloud after a line with --
/hint give the next hint
/idk say “I don’t know”
/teach stop this question and get the lesson
/due list the concepts that are due

The tutor uses the ramabana model call agent.oneshot. Thus [jobs] in config.toml sets its route. Two tools let the coding agent add to the graph while you code. learning_note files a concept that you just met. learning_due lists the concepts that are due.

State and display

_st keeps one store, one tutor and one open session for the terminal. The store and the tutor start on first use.

show_q and show_r make terminal text from a question and from a result.


source

show_r

def show_r(
    r
)->str:

A result as terminal text.


source

show_q

def show_q(
    q
)->str:

A question as terminal text.

Commands

find changes the argument of /learn into a slug. learn starts a session.


source

learn

def learn(
    agent, arg:str=''
):

source

find

def find(
    lr, arg
)->str | None:

The slug for arg: a slug, else the best concept hit in search, else None.

These commands work on the open question. _need gives an error when no question is open.


source

teach

def teach(
    agent, arg:str=''
):

source

idk

def idk(
    agent, arg:str=''
):

source

hint

def hint(
    agent, arg:str=''
):

source

answer

def answer(
    agent, arg:str=''
):

due lists the concepts that are due for review.


source

due

def due(
    agent:NoneType=None, arg:str=''
):

Tools for the agent

The coding agent calls these tools. Their docstrings tell the agent what each tool does.


source

learning_due

def learning_due()->str:

The concepts the user has due for review.


source

learning_note

def learning_note(
    name:str, statement:str, subject:str='code', prereqs:str=''
):

File a concept the user met while coding, so abhyasa can ask about it later. prereqs is comma-separated slugs.

Setup

setup registers the commands and the tools. _safe shows an error as text in the terminal.


source

setup

def setup(
    reg
):

Register the commands and tools of abhyasa with ramabana.

Tests

A stand-in registry keeps the commands in a dict. A stand-in agent uses the fake model for oneshot.

from abhyasa.store import temp_learning
from abhyasa.llm import Fake
fake = Fake({'You grade one answer': dict(correct=True, grade=9, first_error='', misconception='', feedback='Yes.')},
            dflt=dict(question='Why sort by score?', answer='To rank.', rubric=['rank']))
class Reg:
    def __init__(self): self.commands, self.tools = {}, []
    def command(self, n, f, help=''): self.commands[n] = f
    def tool(self, f): self.tools.append(f)
agent = AttrDict(oneshot=lambda p, sp='', job='': fake(p, sp))
_st.update(lr=temp_learning(), tutor=None, sess=None)

setup registers all six commands, and ans as a second name for a. An answer with no open question gives a clear message.

reg = Reg(); setup(reg)
test_eq(sorted(reg.commands), ['a', 'ans', 'due', 'hint', 'idk', 'learn', 'teach'])
test_eq(reg.commands['a'](agent, 'x'), 'No open question. Start with `/learn`.')

The agent files a concept. /learn asks about it, and /a grades the answer.

assert 'Filed Ranking' in learning_note('Ranking', 'Order items by a score.', 'ml')
assert 'Why sort by score?' in reg.commands['learn'](agent, 'ranking')
assert '**solid**' in reg.commands['a'](agent, 'to rank them\n-- I think order matters')

A concept that was just answered is not due.

test_eq(learning_due(), 'Nothing is due.')

The tutor follows the newest agent, and an error other than ValueError becomes one line.

agent2 = AttrDict(oneshot=lambda p, sp='', job='': fake(p, sp))
_tutor(agent2)
assert _st.agent is agent2
def boom(agent, arg=''): raise RuntimeError('the vault is busy')
test_eq(_safe(boom, agent2, ''), 'abhyasa could not do that: RuntimeError: the vault is busy')