Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit dfc8c85

Browse files
committed
By default pass current input history to LLMs.
This adds the option to pass all the input to LLM for better context.
1 parent e27a9e2 commit dfc8c85

3 files changed

Lines changed: 90 additions & 16 deletions

File tree

IPython/terminal/interactiveshell.py

Lines changed: 55 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@ def _displayhook_class_default(self):
430430
"Default is `'NavigableAutoSuggestFromHistory`'.",
431431
allow_none=True,
432432
).tag(config=True)
433+
_autosuggestions_provider: Any
433434

434435
llm_constructor_kwargs = Dict(
435436
{},
@@ -439,6 +440,31 @@ def _displayhook_class_default(self):
439440
This is used to – for example – set the `model_id`""",
440441
).tag(config=True)
441442

443+
llm_prefix_from_history = DottedObjectName(
444+
"input_history",
445+
help="""\
446+
Fully Qualifed name of a function that takes an IPython history manager and
447+
return a prefix to pass the llm provider in addition to the current buffer
448+
text.
449+
450+
You can use:
451+
452+
- no_prefix
453+
- input_history
454+
455+
As default value. `input_history` (default), will use all the input history
456+
of current IPython session
457+
458+
""",
459+
).tag(config=True)
460+
_llm_prefix_from_history: Any
461+
462+
@observe("llm_prefix_from_history")
463+
def _llm_prefix_from_history_changed(self, change):
464+
name = change.new
465+
self._llm_prefix_from_history = name
466+
self._set_autosuggestions()
467+
442468
llm_provider_class = DottedObjectName(
443469
None,
444470
allow_none=True,
@@ -453,24 +479,17 @@ class to use for the `NavigableAutoSuggestFromHistory` to request
453479
`stream_inline_completions`
454480
""",
455481
).tag(config=True)
482+
_llm_provider_class: Any = None
456483

457484
@observe("llm_provider_class")
458485
def _llm_provider_class_changed(self, change):
459486
provider_class = change.new
460-
if provider_class is not None:
461-
warn(
462-
"TerminalInteractiveShell.llm_provider_class is a provisional"
463-
" API as of IPython 8.32, and may change without warnings."
464-
)
465-
if isinstance(self.auto_suggest, NavigableAutoSuggestFromHistory):
466-
self.auto_suggest._llm_provider = provider_class()
467-
else:
468-
self.log.warn(
469-
"llm_provider_class only has effects when using"
470-
"`NavigableAutoSuggestFromHistory` as auto_suggest."
471-
)
487+
self._llm_provider_class = provider_class
488+
self._set_autosuggestions()
472489

473-
def _set_autosuggestions(self, provider):
490+
def _set_autosuggestions(self, provider=None):
491+
if provider is None:
492+
provider = self.autosuggestions_provider
474493
# disconnect old handler
475494
if self.auto_suggest and isinstance(
476495
self.auto_suggest, NavigableAutoSuggestFromHistory
@@ -482,14 +501,35 @@ def _set_autosuggestions(self, provider):
482501
self.auto_suggest = AutoSuggestFromHistory()
483502
elif provider == "NavigableAutoSuggestFromHistory":
484503
# LLM stuff are all Provisional in 8.32
485-
if self.llm_provider_class:
486-
llm_provider_constructor = import_item(self.llm_provider_class)
504+
if self._llm_provider_class:
505+
llm_provider_constructor = import_item(self._llm_provider_class)
487506
llm_provider = llm_provider_constructor(**self.llm_constructor_kwargs)
488507
else:
489508
llm_provider = None
490509
self.auto_suggest = NavigableAutoSuggestFromHistory()
491510
# Provisinal in 8.32
492511
self.auto_suggest._llm_provider = llm_provider
512+
513+
name = self.llm_prefix_from_history
514+
515+
if name == "no_prefix":
516+
print("set tofun1", self.llm_prefix_from_history)
517+
518+
def no_prefix(history_manager):
519+
return ""
520+
521+
fun = no_prefix
522+
523+
elif name == "input_history":
524+
525+
def input_history(history_manager):
526+
return "\n".join([s[2] for s in history_manager.get_range()]) + "\n"
527+
528+
fun = input_history
529+
530+
else:
531+
fun = import_item(name)
532+
self.auto_suggest._llm_prefixer = fun
493533
else:
494534
raise ValueError("No valid provider.")
495535
if self.pt_app:

IPython/terminal/shortcuts/auto_suggest.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ class NavigableAutoSuggestFromHistory(AutoSuggestFromHistory):
178178
# This is the instance of the LLM provider from jupyter-ai to which we forward the request
179179
# to generate inline completions.
180180
_llm_provider: Any | None
181+
_llm_prefixer: callable = lambda self, x: "wrong"
181182

182183
def __init__(self):
183184
super().__init__()
@@ -386,9 +387,13 @@ async def _trigger_llm_core(self, buffer: Buffer):
386387
except ModuleNotFoundError:
387388
jai_models = None
388389

390+
hm = buffer.history.shell.history_manager
391+
prefix = self._llm_prefixer(hm)
392+
print(prefix)
393+
389394
request = jai_models.InlineCompletionRequest(
390395
number=0,
391-
prefix=buffer.document.text,
396+
prefix=prefix + buffer.document.text,
392397
suffix="",
393398
mime="text/x-python",
394399
stream=True,

examples/auto_suggest_llm.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,35 @@
3333
In [1]: from examples.auto_suggest_llm import setup_shortcut
3434
...: setup_shortcut('c-q')
3535
36+
37+
Getting access to history content
38+
---------------------------------
39+
40+
This uses the same providers as Jupyter AI, In JupyterAI, providers may get
41+
access to the current notebook content to pass as to the LLM as context.
42+
43+
Here Jupyter AI documents how to get such context.
44+
45+
https://jupyter-ai.readthedocs.io/en/latest/developers/index.html
46+
47+
48+
When reusing these models you may want to pass them more context as well in
49+
IPython to do so you can set the
50+
`c.TerminalInteractiveShell.llm_prefix_from_history` to `"no_prefix"`,
51+
`"input_history"` or a fully qualified name of a function that will get
52+
imported, get passed a `HistoryManager`, and return a prefix to be added the LLM
53+
context.
54+
55+
56+
For more flexibility, subclass the provider, and access the hisotory of IPython
57+
via:
58+
59+
```
60+
ip = get_ipython()
61+
hm = ip.history_manager()
62+
hm.get_range(...) # will let you select how many input/output... etc.
63+
```
64+
3665
"""
3766

3867
import asyncio

0 commit comments

Comments
 (0)