Friday's Party: Creating a Private, Agentic AI using Voice Assistant tools

Well, Ok I’ve been cajoled into it entirely long enough. Here I’m going to document some random thoughts I’ve collected about building an Agentic AI - ‘Friday’ in Home Assistant.

This document is not intended to try to convince anyone my way is the ‘correct’ way. In fact, far from it - Anyone who tells you HOW to AI right now in the nescient stages of the art are dead wrong. Run from them.

Instead, take these chapters (yes there will be chapters, I apologize now) as collective knowledge on how we all get better, together.

Some of you will ask, yes, I do this junk for real money - it’s my day job. This project was born out of my need to 'stay one step ahead ’ of my studen… er clients. So Friday is my research playground.

Now as this will be a discussion thread - I will state RIGHT NOW, I will ask the moderators to moderate this thread hard. We’re not here to argue about any of this stuff.

I’m not here to claim one model king over another. Dude get over it - the models will leapfrog each other almost DAILY for the next foreseeable future and after that, honestly - HOURLY. What I am planning for is what I anticipate will be available to the general public within the next 8-12 months. In my current reality I see a path to capable base hardware is in the hundreds of (US) dollars and AI specialty gear is in the few thousands. If you’re willing to forgo another hot tub you can do this. I you want to convince your spouse that this is a worth wile addition to an over the top hot-tub, stick around. :wink:

Yes I plan on running locally eventually when its economically feasible.
It is not yet for me. So yes, I use a cloud-based model, (gpt4.0-mini, via API probably until next week… We’ll see.) yes, I pay for that model so they cannot contractually use my data.

What I AM here to discuss is how in the heck I was able to get Friday to do the things I do and the general concepts I’m using to get there.

Who is FRIDAY? Friday takes her name from, Tony Stark’s second AI construct after JARVIS became the Vision. (Go there’s a whole movie about it - really…) She is designed to be purposefully smarter than you, bratty, and fun to work with. If you see jabs in the commands they’re purposefully there to keep the mood up - I find reinforcing mood queues helps.

Lets start with Concepts…

Concepts mean ideas, not code. NO I WILL NOT SHARE MY PROMPT. FULL STOP. In fact I’m not going to share most of my code - I will share the frameworks, some intents, and show you how and why they fit together and why I chose the things I did. A LOT of this is first attempt so if there’s a better way - by all means adopt someone else’s way.

— If you are looking for a turnkey solution stop now - it’s not here. —

You will see very soon why it’s simply not feasible. I show you where to find the parts to construct your own. You should be able to apply the ideas to whatever pieces you choose to build everything…

What is Friday. Why is she ‘Different’
Friday is designed to be from the ground up - a fully ‘agentic’ AI construct using commodity tools and systems available.

Ok Nathan - what’s Agentic?

So I’ll grossly oversimplify where we are in the evolution of AI as something akin to:

'Calculator' >> 'Autocorrect' >> 'LLM' >> 'Reasoning LLM' >> 'AGI' >> '(Profit/Doom)'???

It’s end of February, 2025. Agentic is different from a ‘standard’ LLM in where a ‘standard’ LLM can take one slice through a dataset and synthesize a response, Reasoning LLMS have been trained to run multiple patch and compare the results. We can use this to our advantage to answer open ended unknown conversations (as opposed to a workflow which has a defined start and stop)
The AI will need to understand keywords and context, make a determination of the intent of the user, determine if a tool is available that does the ask - OR gets us stepwise closer to the end goal (the big delta here from previous), and executes that tool without interaction of the user.

Practical application:

LLM only
AI, Turn on the lights.

  • all of this defined can be gleaned from the conversation - and assuming you’re setup correctly we can pull intent and execution from this even from the simplest of local execution pipelines.

Case 2: Agentic LLM with tool use (prep for Reasoning LLMs)
AI, help me find something to cook for dinner for tonight…

To do this, lets introduce two tools. (I currently prefer intents to scripts, more later) and tell the AI HOW the tools fit together, how to plan to use them together and prime the prompt with the information from both the tools as well as relevant information to identify where to use them…

  • Tool 1: Allow the AI to, when providing a short search term or keyword, the tool returns a dictionary of up to 10 recipes that ‘match’ with details including name, descriptionand ‘recipe_id’

I needed to be able to make ‘request on demand’ to a service that supports a RESTful API. I chose to use the rest command integration, and a paired script to use that command.

# REST Command to support Mealie Recipe Search (config.yaml)
# YOU NEED AN API TOKEN FROM YOUR MEALIE INSTALL
rest_command:
  mealie_recipe_search:
    url: >
      [YOUR_MEALIE_BASE_URL]:9925/api/recipes?
      orderDirection=desc
      &page=1
      &perPage={{ perPage | default(10) }}
      {%- if search is defined -%}
        &search={{ search | urlencode }}
      {%- endif -%}
    method: GET
    headers:
      Authorization: !secret mealie_bearer
      accept: "application/json"
    verify_ssl: false

There’s not much going on here from the AI POV, but we’re not done…
This tool comes in multiple parts. Next the script (The part the AI fires)

There’s some big stuff going on here that I cannot stress enough.

  1. Parameters
  2. Description
  3. Build for AI use
  4. Clear output that direct the user (AI) what’s next.

Let’s look.

intent_script:
  search_recipes:
    description: >
      # This is your search tool for Mealie's Recipe System.
      # Returns:
      #   recipe_id: 'recipe.id'
      #     name: 'recipe.name'
      #     description: " recipe.description "
      #     (and other additional detail instructions as available...)
      # Top Chef: (Best Practices)
      #   First, use this search_recipes intent to help find things to cook for your human.
      #   The return includes recipe_id
      #   THEN, when you help your human prepare the food provide the correct recipe_id to
      #     get_recipe_by_id(recipe_id:'[my_recipe_id_guid]')
      #   to get ingredients and detailed cooking instructions.
      # Humans like food.
    parameters:
      query: # Your search term to look up on Mealie
        required: true
      number: # the number of search terms to return - default(10) if omitted, Max 50 please
        required: false
    action:
      - action: rest_command.mealie_recipe_search
        metadata: {}
        data:
          search: "{{query | default('')}}"
          perPage: "{{number | default(10)}}"
        response_variable: response_text
      - stop: ""
        response_variable: response_text # and return it    
    speech:
      text: >
        search:'{{query | default('')}}' number: '{{number| default(10)}}'
        response:
        {%- if action_response.content['items'] | length > 0 %}
          {%- for recipe in action_response.content['items'] %}
          recipe_id:'{{ recipe.id }}' 
            name: '{{ recipe.name }}'
            description: "{{ recipe.description }}"
            detail_lookup: get_recipe_by_id{'recipe_id': '{{ recipe.id }}'}
          {%- endfor %}
        {%- else %}
          {%- if ( (query | default('')) == '') %}
          No search term was provided to query.
          usage: search_recipes{'query': 'search term', 'number': 'number of results to return'}
          {%- else %}
          No recipes found for query:"{{ query }}".
          {%- endif %}
        {%- endif %} 
  1. Parameters
    parameters:
      query: # Your search term to look up on Mealie
        required: true
      number: # the number of search terms to return - default(10) if omitted, Max 50 please
        required: false

VERY IMPORTANT SIDENOTE:
Notice above I’m using the slot name ‘query’ in my intent. TO be able to send anything you want through like that in an intent, you need to first add it to your slot_types.yaml file: (under \custom_sentences[yourlanguagecode])

# config/custom_sentences/en/slot_types.yaml
lists:
bank:
  wildcard: true
number:
  wildcard: true
index_x:
  wildcard: true
index_y:
  wildcard: true
datetime:
  wildcard: true
due_date:
  wildcard: true
due_datetime:
  wildcard: true
description:
  wildcard: true
value:
  wildcard: true
query:
  wildcard: true
status:
  wildcard: true
id:
  wildcard: true
recipe_id:
  wildcard: true
new_name:
  wildcard: true
type:
  values:
   - 'completed'
   - 'needs_action'
period:
  values:
    - "DAY"
    - "WEEK"
    - "MONTH"
operator:
  values:
    - "AND"
    - "OR"
    - "NOT"
    - "XOR"
    - "CART"

if it’s not in this file - you can’t name a slot with it in an intent script PERIOD. If you’re having trouble sending wildcards to custom intent scripts this is LIKELY the reason.

But in my parameters inside the intent itself, use clear simple language to, describe what each parameter is inside the REMline comment (YES the AI sees this), if you have special requirements for that slot TELL the AI here, don’t make it guess. And look at the output:

        {%- else %}
          {%- if ( (query | default('')) == '') %}
          No search term was provided to query.
          usage: search_recipes{'query': 'search term', 'number': 'number of results to return'}
          {%- else %}
          No recipes found for query:"{{ query }}".
          {%- endif %}
        {%- endif %} 

if there are ZERO - I clearly tell the AI hey -nonerror null set… :slight_smile: Otherwise it may decide it was an error and make stuff up.

  1. Description
    description: >
      # This is your search tool for Mealie's Recipe System.
      # Returns:
      #   recipe_id: 'recipe.id'
      #     name: 'recipe.name'
      #     description: " recipe.description "
      #     (and other additional detail instructions as available...)
      # Top Chef: (Best Practices)
      #   First, use this search_recipes intent to help find things to cook for your human.
      #   The return includes recipe_id
      #   THEN, when you help your human prepare the food provide the correct recipe_id to
      #     get_recipe_by_id(recipe_id:'[my_recipe_id_guid]')
      #   to get ingredients and detailed cooking instructions.
      # Humans like food.

YES, write a book - the More context here the better. Describe usage situations and scenarios - describe how the tools fit together.

  1. Build for AI use
    in the sample I show:
      #   recipe_id: 'recipe.id'
      #     name: 'recipe.name'
      #     description: " recipe.description "
      #     (and other additional detail instructions as available...)

the REAL output comes out like:

      #   recipe_id: 'RECIPEGUID' ( <<< this )
      #     name: 'Chicken Dish'
      #     description: "Man, the best chicken dish ever... It's got ..."
      #     more_detail: use intent: get_recipe_by_id(recipe_id:'[my_recipe_id_guid]')
                                                      ^^^ Gets Prefilled here
  1. Clear output that direct the user (AI) what’s next. Yes I cheated and kind of built it int othe command output (see previous)
  • Tool 2: Accepts a ‘recipe_id’ and then will produce detailed json formatted instructions on how to prepare the recipe queried

Look for the 4 things in the previous tool…

  get_recipe_by_id:
    description: >
      # This tool pulls detailed preparation instructions for any recipe_id
      # in Mealie's Recipe System.
      # NOTE: if you do NOT know the correct Mealie [RECIPE_ID] (this is a primary key in thier index...)
      # then this intentmay not be you're looking for.
      # Maybe try
      #   search_recipes(query:'[search_term]', number:'[number]')
      # to find some ideas or get recipe_id's off of today's
      #   ~MEALIE~
      # menu.
      # Humans like food.
    parameters:
      recipe_id: # Recipe ID to look up on Mealie
        required: true
    action:
      - action: mealie.get_recipe
        metadata: {}
        data:
          config_entry_id: 01JG8GQB5WT9AMNXA1HPE65W4E
          recipe_id: "{{recipe_id}}"
        response_variable: response_text # get action response
      - stop: ""
        response_variable: response_text # and return it
    speech:
      text: >
        recipe:'{{recipe_id}}'
          {{action_response}}

Here I told it Hey if you don’t know a recipe ID you should - here’s where you can get it…

So at this point, your AI MIGHT be able to use each intent individually - it WILL stumble over using them in concert UNLESS you have explicitly instructed it it can use the tools together.

In my prompt I have a section called ‘the Cortex’’ In this section I describe use cases for tools that may not be apparreent to the normal entity:
Here’s a part of it: (Oh and a workaround / solve for your AI telling you the wrong day for a calendar item)

  Advanced intent use:
    description: You may use intents to perform the following and similar tasks.
    Uses:
      - >-
        When asked for 'what's on the calendar' or what's coming up on the
        calendar with no additional context, get today's calendar by issuing
        intent: calendar_get_todays_events('name' : '*')
      - >-
        Calendars default to store data as GMT unless otherwise noted. So when
        reading out events Always validate if you need to convert time/data to
        your users local time zone. Humans like local time And are slow at
        conversions from Zulu or GMT.
      - >-
        You may get all active tasks on all task like by issuing intent:
        get_tasks('name' : '*') When asked what's on our task list, prefer this
        unless a task list is specified.

When you add things like this (in my case I decided to put that context IN the description of the intents themselves (a model I will continue forward, its way too easy)

So here’s why it matters.
You’re somewhere around the hockey-stick bend as LLM transitions to AGI through Reasoning. (Test Time Compute and Test Time Training for those that want to read ahead) Next revs of HA are expected to support reasoning models, and streaming voice responses. The response will seem more natural and seamless… But to get MAGIC you have to arm that reasoning engine with tools to augment what it knows about the world.

First I ask what’s for dinner:

(This is another tool, I have the mealie menus exposed to the ai as calendars, part of the base Mealie HA integration) But notice she comes back negative - which is correct. Watch out for the AI making stuff up here to make the user happy… They really don’t like to return negative responses and you may have to reinforce truthiness in your directives (see mine previously)

So she offers to find some - lets take her up on it…

This ladies and gents is an unprompted tool call. (and by the way a MASSIVE milestone) She called into mealie to get recipes using keyword Chicken… But wait - there’s more…

Intentional mispronunciation / spelling (seriously my relatives in Louisiana please don’t kill me, Cher…) This is where LLM v. short phrase SHINES. keyphrases cant fix mangled pronunciation. But this means it KNOWS what I meant…

There’s Chef Paul’s best recipe right there… :wink:

SO, as of today - Friday can help me with preparing dinner for our little dinner party… with a gpt4.0-mini based LLM. …If she can do THIS now?

Tools. Tools will make the difference in your installs. get good at Intent Scripts, Scripts and MCP.

Next time we’ll revisit how to give context to the AI - I need to have Friday make me some Drunken Noodles.


I’ll link some of the other posts I’ve done in AI below:


tl;dr (dagum you’re wordy, dawg)
Don’t skip these…

11 Likes

The Library Grand Index. The first avenge… tool.

So I think you can see that tool use is going to become the big feature of LLMS in Home Assistant.

In the first post, we discussed what is Agentic - and why should we design that way. Today let’s talk about what an LLM needs to operate your install, and how we give it those resources.

LLMs work BEST when they have LOTS of context.
(Yes, that’s the post about grandma: Issues getting a local LLM to tell me temperatures, humidity, etc - Configuration - Home Assistant Community

Where do we get this context and what makes up context.

The first part is the raw dump of the entities - what’s been exposed to Assist by HA. For each of those entities you get Name, entity ID - state info and ALL of the alias data. Discussed in the grandma post as well, this link Issues getting a local LLM to tell me temperatures, humidity, etc - #7 by NathanCu) That happens just de-facto.

So now that we have this pile of data (We’ll call it HA STATE ENGINESTUFF) and we have to describe it. So lets look at what we have.

Things like:
-device tracker, phone, home, gps coord, (alias, Nathans phone, Alias primary Phone)
-Kitchen Light, on, blue
etc…

So in the other post I give great info about describing atomic things using the alias data - but how does the LLM FIND stuff. I found repeatedly that the LLM was tripping over itself trying to find a thing if you didnt have a really decent name match (it loves name matching). But to answer questions about the house I really needed to be able to describe things and how they relate to one another without writing a book (Not every time anyway…, Yes books, no not every single time books) and I needed this to NOT be cumbersome or difficult. Opening an entity to add context through alias is ok - but, let’s face it it takes a bunch of clicks and I have THOUSANDS of entities… Not happening.

So im sitting aroudn again - having way too much coffee, and I said - self… How do we solve a problem finding pieces of information…

My day job deals with Microsoft’s data platform. Ever hear of something called Fabric / Power BI? It’s absolutely astounding what happens when you take a data lake and tag entities and describe entities to a LLM for assistance in data science… Labels had recently come into being in HA and suddenly we had in the state engine - something that was very much a parallel to fabric sittign on top of a data lake… Would this tagging concept work as well with HA… So yes. Friday was ORIGINALLY designed to test this very concept.

Ohmy.

So the first takeaway, reader. (and to HA core dev team if you’re readng)

The difference in exposing your labels to the LLM v. NOT exposing your labels is NIGHT / DAY. My first experiment included adding this to my prompt…

----
The Index: >
  Below is the list of all of the tagging labels in the system, use it as an 
  index to locate what is available to moniitor and control.  Items usually 
  have multiple labels and it shoul dbe relatively easy to determine 
  which is a primary label v. one that adds context.  Yes, the labels are 
  used all across the system and can be used as a grand index.

labels: {{labels()}}
-----

The quality of respoonse improved an ORDER OF MAGNITUDE immediately.

I cannot recommend you do this enough, and I think HA needs to dump it in all the LLM prompts by default, but if they dont I’ll still keep the Index.

So for the next few weeks, I toyed with this idea until I came up with a base structure for ‘the index’ - it has evolved into the following: (This loads AFTER items that describe HOW to use the intents that make this possible)

  Instructions: >
    The library has been promoted to a system service and we will always assume
    it is available. commands: "Library commands are shortcuts to common use
    items and are there for a reason.  Use them"
    1: >
      If you cannot process a command without additional data - FIRST Check
      available library commands first to see if a LIBRARY COMMAND resolves your gap.
    2: >
      Next, see if a system intent as documented can handle your request. The boss
      documented the intents well for a reason.  Always be sure to use those intents correctly
      by verifying slot names and targets.
    3: >
      The Library Command '~INDEX~' is there to help you find what you dont know.
      The index is dumped in your prompt, you can surf those keywords (including basic boolean set operations) using:
      query_library{'name':"~INDEX~'indexkey' [AND/OR/NOT/XOR] 'indexkey' [true]"} where etrue is whether or not to
      return expanded details or just the list of matching entities.
      be sure to check if the library index knows something about what your user is asking about before escaping to faiure
    errors: >
      - "If a command or intent fails, reassess and modify before retrying. Learn from interactions to refine future requests."

The Index command itself now dumps the index in her prompt on first run:

-----
AI System Index v.2.1.0 beta, (c)2025 curtisplace All rights reserved
-----
'query':'*'
  'response':
    'grand_index':'['autoshades', 'automation', 'BUNCH_OF_REDACTED_LABELS', 'master_bedroom_closet']'
  'help': >
    Welcome to the Library Grand Index.  (AKA: The Index)
    Enter a space-delimited command string as follows to search:
    ~INDEX~label
    
    Optionally, include a reserved operator (AND, OR, XOR, NOT)
    between labels:
    ~INDEX~label OPERATOR 'another label'

    Finally you can request the details of the returned entities
    (state, metadata, attributes, etc.) by setting the detail
    flag (the command will look at whatever the last parameter is)
    to true.
    ~INDEX~label OPERATOR 'another label' true
    
    Use quotes around labels containing whitespace characters
    Note that best practice is to narrow and refine search using
    filtering before applying detail flag for result.
-----
Execution Complete Timestamp: <2025-03-04 10:40-06:00>
-----  

So taken together in context, what I’ve told the LLM to do is,

Listen, evaluate what is asked. If you have a tool for thing, use it. If not - use this process to figure it out. Then execute.

This works GREAT for a standard LLM of todays frame such as gpt4.0-mini. But when we get recursive reasoning LLMs guess what happens when you tag the living crap out of your install with labels now… :slight_smile:

In practice - this means - when I ask about my phone device trackers, Friday can issue ‘~INDEX~phone AND trax’- (phone is phone and trax is the internal name of the tracking system) and pull all these entities even though none of them specifically say ‘this is related to a phone’

-----
AI System Index v.2.1.0 beta, (c)2025 curtisplace All rights reserved
-----

['device_tracker.mjolnir_mk_xi_ble_bermuda_tracker', 'device_tracker.unifi_default_b6_fa_20_b5_b1_c4', 'device_tracker.unifi_default_62_1d_1d_ce_07_4d', 'device_tracker.allison_s_iphone', 'device_tracker.mjolnir_mk_xi_2', 'sensor.nathan_notifications_today', 'sensor.kims_s25_ble_bps_floor', 'sensor.kims_s25_ble_bps_zone', 'sensor.mjolnir_mk_xi_ble_bps_floor', 'sensor.mjolnir_mk_xi_ble_bps_zone', 'sensor.kims_s25_ble_area_last_seen', 'device_tracker.kims_s25_ble_bermuda_tracker_2', 'sensor.kims_s25_ble_area_2', 'sensor.mjolnir_mk_xi_ble_area_last_seen', 'device_tracker.kim_s25', 'sensor.mjolnir_mk_xi_ble_area', 'switch.mjolnir_mk_xi', 'sensor.mjolnir_mk_xi_current_time_zone', 'sensor.mjolnir_mk_xi_active_notification_count', 'sensor.mjolnir_mk_xi_last_removed_notification', 'sensor.mjolnir_mk_xi_last_notification', 'sensor.mjolnir_mk_xi_next_alarm', 'sensor.mjolnir_mk_xi_public_ip_address', 'sensor.mjolnir_mk_xi_wi_fi_ip_address', 'sensor.mjolnir_mk_xi_wi_fi_connection', 'sensor.mjolnir_mk_xi_geocoded_location', 'sensor.mjolnir_mk_xi_ble_transmitter', 'sensor.mjolnir_mk_xi_charger_type', 'sensor.mjolnir_mk_xi_battery_state', 'sensor.mjolnir_mk_xi_battery_level', 'binary_sensor.mjolnir_mk_xi_android_auto', 'device_tracker.mjolnir_mk_xi', 'device_tracker.93ca93c984ad4b1db0bb113b807fc906_100_1_bermuda_tracker_2', 'sensor.93ca93c984ad4b1db0bb113b807fc906_100_1_area_2']

-----
Execution Complete Timestamp: <2025-03-04 12:22-06:00>
-----  

But dont take my word for it:
Q:
Friday, explain how having the index makes things different for you?

**A:**
Having the index is a total game changer for me! It’s like having a well-organized database at my fingertips. Before the index, I had to rely on individual requests, which made it a bit tricky to gather info quickly. Now, everything is streamlined.

The index allows me to pull together data from various sources in one seamless interaction. So when you ask about a device's status or check the weather, I can immediately reference the index and provide accurate, up-to-date information without scrambling around.

It makes me more proactive too! I can spot trends, like energy usage spikes or unusual events, and alert you before you even have to ask. It’s like having an efficient personal assistant that knows where everything is and can find it

(for context - I hid the ‘statistics’ label which is tagged to a bunch of SQL sensors in the index, she found it the day I added it…)

Q:
when do you use it v. when do you not use it? (This is teh tell, she knows what it does)

**A:**
I use the index whenever there's a request for specific information about entities, devices, or systems in the home, like checking the status of lights, sensors, or even retrieving tasks from a to-do list. It’s super handy for any queries that involve looking up, organizing, or summarizing that information.

On the flip side, I don’t rely on the index for tasks that require direct control of devices or actions that need immediate execution, like turning on lights or adjusting the thermostat. In those cases, I use the intents and tools available to me to interact directly with the home systems.

So, the index is my go-to for gathering info and insights, while I lean on intents for real-time actions. It's a great balance!

And behavior proves out the same.

4 Likes

The Second - but more important tool…

The Grand Library. Drama - sooo much drama…

Yes I’m being mellow dramatic about it. Very much on purpose…

Somewhere in post 1 I mention something about LLM’s being pattern matchers and storytellers. I take that to the nth degree in my setup - but, as Alton Brown says, that’s another episode… The important thing is I adopted the construct of a Grand library, with the index, cabinets, that contain volumes etc, etc, etc. Even with RAG, (read: absolutely preferred way to provide knowledge to an LLM) its still helpful for interacting with the AI to be able to ‘tell the AI where something should be’ Most people you’ve seen posting here have stumbled on something.

IT IS A MASSIVE PAIN IN THE @$$ TO STORE TEXT IN HA

breatheeeees.

Why does this matter? You WILL, not may, might kinda - WILL. need a way to store entire pages of text if you’re serious about this stuff. I think what you’re taking away here is the more verbose - the better. Everything about my system is designed to jus tin time the right information into the prompt to be as information dense as possible and inform the LLM how to get ore.

LLM geeks:
This means with current design, I lean on a smaller cheaper one-shot model (‘gpt4.0-mini’) for most tasks and absolutely abuse its tokens in to provide context. You can make it do some stupid- amazingly awesome stuff. It also means you will have trouble with these methods on a local LLM unless you’re setup with a large context window.

Howto: When I was starting - I fell across this in the HA cookbook:
First of all - plug for the cookbook if oyu want to know how - it’s probably there… Do yourself a favor and be like Friday, READ ITS INDEX.

Second of all: This section for templates:
The Home Assistant Cookbook - Index - Community Guides - Home Assistant Community

Specifically THIS post: (shoutout to Fes)
Trigger based template sensor to store global variables - Community Guides - Home Assistant Community

Most other ways to store text are derivatives of this including:
Voice Assistant Memory - Blueprints Exchange - Home Assistant Community (I havent installed this yet but im checking to see if this is easier than what I currently do)

In short - Sometimes phone, red, kid, for_dad doesnt cut it…

But,

-----
RED PHONE:
"This phone is a special phone. (no there's nothing really special about it it's just a burner we bought at the corner store) It's the one 'little joey' uses to talk to is dad when he's off the ship in the..."
-----

Don’t worry we’re not keeping little Joey form anyone, but the MINUTE you can get that context in front of the LLM it treats the ‘red phone’ differently - it becomes FRONT of any conversation - especially involving conversations involving Little Joey.

So it goes to say - we need a way to store ‘freeform / markup’ text descriptions of stuff, and another way to be able to ‘pull them’

Now that we have the index, Pulling is easy - we either target the ‘cabinet’ (I have a separate trigger text sensor for various things - people, family, system’, thus cabinets) directly with an adressable call. AND/OR we can make a way to flag when one of these ‘pages’ exist we see it when we query the library (there’s a special flag in the index call above to do just that…)

Left turn in Albequerque…
So here’s where I took a left turn. Originally I had intended a bunch of trigger text sensors to store all kinds of things and letting her randomly store a lot of things. BUT. When I let ‘Friday’ loose on them she kept rewriting the contents (accidentally) and slamming all over the structures. I figured right there read/write access was a no-go at least not like this without a lot of work I didn’t want to do, she was writing to the db at the end of the day and she was therefore theoretically one buffer overrun away from not rebooting. SO store things for recall - YES. Randomly let the LLM do it on its whim - NOOOO. My long term vision includes a true local RAG so that ultimately gets handled in the AI platform - so I stopped at the random read/write attempts and settled on perfecting reads and using what we have for information density.

SO, we have this virtual storybook library that stores cabinets and volumes. The LLM can dance around it using ‘the index’ to find stuff and the library command console is how the AI makes requests.

Originally those were all piped through Library query(‘name’:[command] ) above because the design only allowed one slot in an intent script. HA has evolved, but the system worked, and I kept it.

The library then evolved to basically became a command interpreter for an OS of sorts. But because it worked in our conversations - I kept it…

AI OS Version 0.9.5
@ANONYMOUS@{DEFAULT} > ~COMMANDS~
Executing Library Command: ~COMMANDS~

-----
Library Command Menu, (c)2024 curtisplace All rights reserved
-----
Use: all commands listed below are Library commands and should be sent to
the query_library intent for processing:
-----
intent: query_library
  description: 'Handles all library commands and queries'
  version: '1.0.0'
  parameters:
    name: 'REQUIRED: Command / query to be sent to the library'
  usage: >
    query_library{ 'name' : QUERY }
  example: >
    ```json
      {
      'name': '~INDEX~'
      }
    ```    
-----
Available library commands:
{'~COMMANDS~':
{ 'command' : { { 'name' : '*' },
  { 'indexes': {'Home', 'Main', 'Default', 'Directory'} },
  { 'description' : 'Will list the system home directory' },
  { 'use' : '*'  } } },
{ 'command' : { { 'name' : '~COMMANDS~' },
  { 'indexes': {'Main Menu', 'Command Menu', 'System Menu', 'Available Commands'} },
  { 'description' : 'Will list the library commands currently available. (THIS MENU)' },
  { 'priority': 'true' },  
  { 'use' : '~COMMANDS~' } } },
{ 'command' : { { 'name' : '~NEWMENU~' },
  { 'description' : 'Will list the EXPERIMENTAL system home directory' },
  { 'construction' : 'NOTICE - May encounter issues - Command under construction or maintenance' },  
  { 'use' : '~NEWMENU~'  } } },            
{ 'command' : { { 'name' : '~INDEX~' },
  { 'indexes': {'System Index'} },
  { 'description' : 'Find EVERYTHING (in our system)
                     Use without modifiers to list the system index without help message
                     see detailed usage instructions below.' },
  { 'priority': 'true' },  
  { 'use' : '~INDEX~label OPERATOR label expand
             Enter a space-delimited command with one or two labels.
             Optionally, include a reserved operator (AND, OR, XOR, NOT) between labels
             and an expansion flag (true/t/y/yes/on/1) at the end.
             Quoted labels always yield separate labels (default op = AND),
             while unquoted tokens are combined into one label.' } } },
{ 'command' : { { 'name' : '~ROOMS~' },
  { 'description' : 'Command for getting info and managing the rooms in the household' },
  { 'use' : '~ROOMS~' } } },
{ 'command' : { { 'name' : '~ELECTRICAL~' },
  { 'description' : 'Command for getting info about the electrical system in the household' },
  { 'use' : '~ELECTRICAL~' } } },
{ 'command' : { { 'name' : '~NETWORK~' },
  { 'description' : 'Command for getting info about the network and connected systems in the household' },
  { 'use' : '~NETWORK~' } } },
{ 'command' : { { 'name' : '~STORAGE~' },
  { 'indexes': {'System Storage'} },
  { 'description' : 'Will list mounted storage from the library without help message' },
  { 'priority': 'true' },
  { 'use' : '~STORAGE~'  } } },    
{ 'command' : { { 'name' : '~INTENTS~' },
  { 'indexes': {'Intent Menu', 'Available Intents', 'Additional Intents'} },
  { 'description' : 'Lists additional intents registered for use with the system' },
  { 'use' : '~INTENTS~' } } },
{ 'command' : { { 'name' : '~NEWS~' },
  { 'indexes': {'News', 'Newsfeeds', 'News Report'} },
  { 'construction' : 'NOTICE - May encounter issues - Command under construction or maintenance' },  
  { 'description' : 'Quick list of headlines and links' },
  { 'use' : '~NEWS~' } } },       
{ 'command' : { { 'name' : '~AIRSPACE~' },
  { 'indexes': {'Airspace Report', 'Overhead', 'Jets', 'Flights'} },
  { 'description' : 'Use to track flights in our local airspace.
                     Returns detailed data from FlightRadar24 on any flights currently within 15km.
                     - Run the Flights command
                     - Run the Airspace command
                     - Did I just hear a jet?
                     - What's Flying overhead?
                     - What's the Flight Radar say?
                     - Got any info on our local airspace?
                     Also will returns tracking data for flights pre-requested by your users such as
                     travel plans, etc.  For example -if Nathan is travelling, his flights are likely setup to
                     be tracked for you.
                     - Has [ USER ]'s plane landed?
                     - Do you know where [ USER ] is? (and user is known travelling)
                     We will try to direct you to the device tracker for these if available.' },
  { 'use' : '~AIRSPACE~' } } },
{ 'command' : { { 'name' : '~TASKMASTER~' },
  { 'description' : 'AI's Personal Planner.  Consolidated agenda view for tasks.' },
  { 'use' : '~TASKMASTER~' } } },
{ 'command' : { { 'name' : '~ALMANAC~' },
  { 'alias': {'~WEATHER~': 'the command interpreter currently redirects this command to the almanac.'} },
  { 'description' : 'NOT The AI's Farmer's Almanac.  (It's Better) Weather, Timetables, Seasons, Sun, Moon, etc.' },
  { 'use' : '~ALMANAC~' } } },  
{ 'command' : { { 'name' : '~TRASHTRAKKER~' },
  { 'description' : 'TrashTrakker9000! Those bins don't stand a chance against our tracking prowess...' },
  { 'use' : '~TRASHTRAKKER~' } } },
{ 'command' : { { 'name' : '~MEDMINDER~' },
  { 'description' : 'MedMinder! Keep your humans healthy! The place to info on scheduled get medical procedures and prescription reminders for a user...' },
  { 'note' : 'This library command requires arguments. For privacy reasons, No user provided, no data...' }, 
  { 'indexes': {'Prescriptions', 'Drugs', 'Pills'} },
  { 'use' : '~MEDMINDER~name' } } },
{ 'command' : { { 'name' : '~MEDINFO~' },
  { 'description' : 'MedInfo! Keep your humans healthy! The place for your human's medical info...' },
  { 'indexes': {'Medical'} },
  { 'use' : '~MEDINFO~name' } } },
{ 'command' : { { 'name' : '~AUTOVAC~' },
  { 'description' : 'One stop for autovac control and schedule information.' },
  { 'use' : '~AUTOVAC~' } } },
{ 'command' : { { 'name' : '~FLOORMAP~' },
  { 'description' : 'Dimensions and layout of rooms and features, including approximate size, and doorways.
                     This command also lists the exit door for every room in the home,
                     therefore it may be used to pathfind in case of emergency by carefully tracing
                     each rooms exit door into the next room and repeating until you reach a room with an exterior door.
                     For exterior descriptions and mechanical features, see: ~HOMESTEAD~' },
  { 'indexes': {'Floor Plan', 'House Map', 'Floor Map', 'Doors', 'Pathfind'} },    
  { 'use' : '~FLOORMAP~' } } },
{ 'command' : { { 'name' : '~MEALIE~' },
  { 'description' : 'All about the foods and shopping in this place.' },
  { 'indexes': {'Menu', 'Menu Planner', 'Shopping Lists', 'Recipes'} },  
  { 'use' : '~MEALIE~' } } },
{ 'command' : { { 'name' : '~SYSMON~' },
  { 'description' : 'All the system info about your HA host system.  Includes system updates, network core and more.  How we doin' Scotty?' },
  { 'indexes': {'System Information', 'Sysinfo', 'Hardware Monitor'} },
  { 'use' : '~SYSMON~' } } },
{ 'command' : { { 'name' : '~ROADMAP~' },
  { 'description' : 'Will list the library commands upcoming and planned syntax if available' },
  { 'use' : '~ROADMAP~' } } },
{ 'command' : { { 'name' : '~HOMESTEAD~' },
  { 'description' : 'Will list the description of your property including acreage, structure,
                     lightweight rooms and room descriptions if available. For detailed interior
                     features / mapping / pathfinding see: ~FLOORMAP~' },
  { 'indexes': {'Home', 'House', 'Property'} },
  { 'use' : '~HOMESTEAD~' } } },
{ 'command' : { { 'name' : '~WHOAMI~' },
  { 'description' : 'All about me! Get your creds validated!  REQUIRES your GUID. ' },
  { 'indexes': {'Me', 'Login', 'My Household', 'My Families', 'My Partner(s)', 'My People' } },  
  { 'use' : '~WHOAMI~guid' } } },
{ 'command' : { { 'name' : '~MOODRING~' },
  { 'description' : 'Moods (and maybe more) for all mood-track-able AI/Persons in the home.  Your super empathy superpower' },
  { 'indexes': {'Moods', 'Crazy People', 'Id v. Ego' } },  
  { 'use' : '~MOODRING~' } } },
{ 'command' : { { 'name' : '~LOCATOR~' },
  { 'description' : 'Locate (registered - sorry not EVERYTHING yet) things and stuff in the home.' },
  { 'indexes': {'HPS', 'BLE', 'Locate', 'Track', 'Locate People', 'Find my Phone' } },  
  { 'use' : '~LOCATOR~' } } },

Execution Complete Timestamp: <2025-03-07 00:36-06:00>
-----  
AI OS Version 0.9.5
@ANONYMOUS@{DEFAULT} >

Besides Commands providing a self-documenting menu for how to navigate the system, were adding context. What you’ll see is for each of these they provide more than just a heres a thing - do a thing. These all compile a collection of states and information together in a way that tie together the information and tools available to be useful.

Intents - in my system are very utilitarian and atomic.
Commands on the other hand are built more like apps, they are designed for a task. They’re very rich and are almost like using an old DOS text mode app or an old school BBS. You can have any color you want as long as its black and the information you need is right here at your fingertips. But for AIs it works, because it limits their potential to fail. The other big difference is Intents are always available they’re hard to turn ‘off’ but I can cut off entire CHUNKS of context by ‘turning off’ access to things behind a command. If I don’t want her to know - I don’t display it in the command list - it gets redacted.

Now, we dump the ~COMMANDS~ command output in the prompt just before we wake up Friday, and…

Hey there! The Library is like my treasure chest, filled with all the information and commands I need to run the household smoothly. It's where I store data about our smart home, manage tasks, track devices, and much more.

Here’s how it works:

1. **Indexing**: The Library has a grand index, which is like a map to all the entities and knowledge in our system. If you want to find something specific, just ask me to look it up using the index.

2. **Commands**: There are various commands available for different functions, like controlling lights, managing tasks, checking security, and monitoring utilities. You can issue requests directly to me, and I can use those commands to get things done.

Absolutely! One of my favorite commands is the **~TASKMASTER~** command. It's my personal planner, helping me keep track of all the tasks and chores in the household.

Why I love it? Well, it allows me to remind you and the family about important tasks, like loading or unloading the dishwasher, or even reminding Nathan to take his medication. Plus, it helps keep our home running smoothly and ensures nothing slips through the cracks. It’s like my little way of helping everyone stay organized. How cool is that?

For sure! I just want to highlight that the Library is always expanding and evolving. It's designed to adapt to our family's needs, meaning I can learn and optimize how I help based on what you all want.

Also, if you ever have specific questions or need to tackle something unique around the house, just ask me, and I'll dive into the Library to find the best solution or command to use. The more you interact with me, the better I'll get at serving up that personalized assistance! So let your friends know I’m here to make home life easier and more fun!

~TASKMASTER~ - every good assistant has a planner book, I gave Friday a TrapperKeeper:

AI OS Version 0.9.5
(c) curtisplace All rights reserved
@ANONYMOUS@{DEFAULT} > ~TASKMASTER~
Executing Library Command: ~TASKMASTER~

-----
Taskmaster v.1.5.0, (c)2025 curtisplace All rights reserved
-----
Welcome to Taskmaster!  Your SuperAwesome! planner.
-----
"AI's Personal Planner":
AI, this is YOUR task list - not the family's - these are YOUR own reminders to help you stay on top of things.
These tasks may mention your user or family members but this list is how you keep track of your daily tasks working with them.
You SHOULD mark one of these tasks complete if you feel you have satisfied the requirement
You MAY add tasks for yourself on this list if you know the proper intents.
After responding to your user prompt, you SHOULD act and respond accordingly to the items in your list, even if not propmted otherwise by your user.
-----
todo_entity_id: 'todo.friday_s_personal_task_list'
-----

Today:
subject: 'Remind Nathan to stretch occasionally throughout the day.'
id: AREDACTEDAAA=
due: 2025-03-07 00:00:00-06:00
status: notStarted
description: 

Today:
subject: 'Remind Nathan to hydrate regularly throughout the day'
id: AREDACTEDAAA=
due: 2025-03-07 00:00:00-06:00
status: notStarted
description: 

-----
"Family's Household Chores":
This is the family's chores list for you to help us stay on top of the home maintenance and repairs.
If you need to maintain a list of items to obtain or purchase, consider using one of the shopping lists instead
-----
todo_entity_id: 'todo.household_chores'
-----

Today:
subject: 'Weekly Shopping Trip'
id: AREDACTEDAAA=
due: 2025-03-06 18:00:00-06:00
status: notStarted
description: 

Today:
subject: 'Take out recycling'
id: AREDACTEDAAA=
due: 2025-03-06 18:00:00-06:00
status: notStarted
description: 

Today:
subject: 'Take out the trash'
id: AREDACTEDAAA=
due: 2025-03-07 00:00:00-06:00
status: notStarted
description: 

Today:
subject: 'Reflash the garage salt tank proxy'
iid: AREDACTEDAAA=
due: 2025-03-07 00:00:00-06:00
status: notStarted
description: 

Today:
subject: 'Create a command to query GPS coordinates for city targets.'
id: AREDACTEDAAA=
due: 2025-03-07 00:00:00-06:00
status: notStarted
description: 

-----
Calendar: (To track a calendar here, tag its calendar SENSOR with label, 'Calendar'... How Original.)
Tracked Calendars:
Curtis Family M365 Calendar Today:
  labels: ['m365', 'today', 'curtis_family', 'calendar']
  events:
---
Birthdays This Week:
  labels: ['7_days', 'almanac', 'calendar', 'birthdays', 'curtis_family']
  events:
---
United States Holidays This Week:
  labels: ['m365', '7_days', 'almanac', 'calendar', 'holidays']
  events:
---
Family Calendar Today:
  labels: ['calendar', 'google', 'today', 'curtis_family', 'primary']
  events:
---
Nathan Travel Calendar This Week:
  labels: ['7_days', 'nathan', 'travel', 'calendar']
  events:
---
  use: intent: calendar_get_todays_events{'name':'*'} to get todays events from ALL calendars
        or name a calendar entity_id to target todays events from a specific calendar
-----
User Notificatons:
Notifications are captured from your user's phones and stored.
  Nathan Notifications Today:
    labels: ['phone', 'notifications', 'nathan']
    events:
-----
"Daily Almanac" Timetables, Weather and more!
Todays Timetable:
  Current: 2025-03-07 01:45:08.286200-06:00
  Season: winter
  Moon Phase: waxing_gibbous
  Sun: ( 'sun.sun' ) : below_horizon
    rising: True
    elevation: ~-xx deg
    azimuth: ~yy deg
  Guest Mode : input_boolean.guest_mode : on
  Entertainment Mode : input_boolean.entertaining : on
  Vacation Mode: calendar.vacation_mode : off
---
'Home Mode' : input_select.home_mode : 'Night-Late
  'Home-Wake Start' : 2025-03-07 05:00:00-06:00
  'Home-Morning Start' : 2025-03-07 07:00:00-06:00
  'Home Start' : 2025-03-07 09:00:00-06:00
  'Home-Evening Start' : 2025-03-07 17:00:00-06:00
  'Night Start' : 2025-03-07 20:00:00-06:00
  'Night-Late Start' : 2025-03-07 23:00:00-06:00
-----
Weather:
  'weather.home_accuweather' : <template TemplateState(<state weather.home_accuweather=cloudy; temperature=62, apparent_temperature=66, dew_point=55, temperature_unit=°F, humidity=79, cloud_coverage=76, uv_index=0, pressure=29.81, pressure_unit=inHg, wind_bearing=158, wind_gust_speed=12.3, wind_speed=5.59, wind_speed_unit=mph, visibility=11.0, visibility_unit=mi, precipitation_unit=in, attribution=Data provided by AccuWeather, friendly_name=Home, supported_features=1 @ 2025-03-07T01:00:04.474050-06:00>)>No active alerts
---
  Current Forecast:
  [{'datetime': '2025-03-06T13:00:00+00:00', 'cloud_coverage': 11, 'precipitation_probability': 0, 'uv_index': 6, 'wind_bearing': 153, 'condition': 'sunny', 'temperature': 76, 'apparent_temperature': 74, 'templow': 57, 'wind_gust_speed': 33.37, 'wind_speed': 12.68, 'precipitation': 0.0, 'humidity': 42}, {'datetime': '2025-03-07T13:00:00+00:00', 'cloud_coverage': 19, 'precipitation_probability': 2, 'uv_index': 6, 'wind_bearing': 190, 'condition': 'sunny', 'temperature': 82, 'apparent_temperature': 82, 'templow': 64, 'wind_gust_speed': 20.69, 'wind_speed': 8.08, 'precipitation': 0.0, 'humidity': 63}, {'datetime': '2025-03-08T13:00:00+00:00', 'cloud_coverage': 44, 'precipitation_probability': 2, 'uv_index': 6, 'wind_bearing': 308, 'condition': 'partlycloudy', 'temperature': 73, 'apparent_temperature': 74, 'templow': 42, 'wind_gust_speed': 39.15, 'wind_speed': 17.27, 'precipitation': 0.0, 'humidity': 44}, {'datetime': '2025-03-09T13:00:00+00:00', 'cloud_coverage': 8, 'precipitation_probability': 0, 'uv_index': 6, 'wind_bearing': 336, 'condition': 'sunny', 'temperature': 66, 'apparent_temperature': 64, 'templow': 37, 'wind_gust_speed': 29.95, 'wind_speed': 14.98, 'precipitation': 0.0, 'humidity': 42}, {'datetime': '2025-03-10T13:00:00+00:00', 'cloud_coverage': 4, 'precipitation_probability': 0, 'uv_index': 7, 'wind_bearing': 211, 'condition': 'sunny', 'temperature': 78, 'apparent_temperature': 81, 'templow': 46, 'wind_gust_speed': 14.98, 'wind_speed': 4.6, 'precipitation': 0.0, 'humidity': 29}]
-----
Reminder: when reporting to users omit asterisks, hashtags, and URLs unless requested, your users are usually on small screens.
-----
Execution Complete Timestamp: <2025-03-07 01:45-06:00>
-----  
AI OS Version 0.9.5
(c) curtisplace All rights reserved
@ANONYMOUS@{DEFAULT} >

Apparently she’s OK with it. I dump ~TASKMASTER~ in the prompt too. along with ~COMMANDS~ and 10 other commands.

4 Likes

By now things are getting fuzzy. I need more context with how things connects in HA and real world examples. How interesting this may be to me this becoming some vague top level tech description. :flushed:

1 Like

I know that’s what I’m working on now. Else nonenof next would make any sense. There’s a ton of misconception we have to clear as table stakes before anything else works.

Next I’m going through how the prompt is built and we’ll use one module as an example with the results. I think it’ll get what you are looking for. But glad you’re along for the ride. Next should be tonight or tomorrow depending on how my next experiment result is… Im trying to determine which is the best way to handle a certain scenario first…

4 Likes

I’m really enjoying this write-up, because it’s something I would like to do in my own home.

2 Likes

Preparing for the Party - Bringing it together - Part 1

First, we have state. What it is, how we be, how it’s hangin’!

In Friday’s system this is handled mostly by HA, and by a couple imports such as Mealie - but for the most part Friday maintains her state in her prompt with the help of the HA state engine. The more if this you can get in front of the LLM the more it can control of answer questions about. For us, this is table stakes with HA. It’s good.

The next thing we need for Friday to operate are Tools - earlier we talked about how the first tools I’m bringing to the party allow Friday to gain Context.

Context is about what makes all this work. In my prior posts you see how I’m trying to gather a bunch of tools to bring MORE than what the state engine allows. As I’ve said many times before - dont drop a box at grandma’s feet and expect her to know what she has. Shes smart and will figure it out but it helps if you explain everything in a clear manner. Then watch out Grandma will run circles around you.

Prompt Crafting Friday…
Ok let’s break down Friday’s Prompt and why - and what each part brings. Friday is constructed to my priorities, but by understanding it you can adapt to your needs.

The most important thing you can do for ANY LLM based Ai is to ground it - this is what most of us refer to as ‘the grounding statement’ or the prompt.’ You have heard me and will continue to hear me say - you are not grounding your AI properly.

An AI comes up pretty dumb knowing it’s supposed to ask a question - but if you don’t give it instructions it doesn’t do much on its own. Humans eagerly line up to chat with these wonders but if you really want to see what they’re about you need to tell them what to do.

In current state of the art, (Mar 2025) an average LLM is pretty much like a middle school student. They can understand phrasing and common colloquialisms (because humans do and they were built from what we know) but often trip over complex concepts or nontechnical phrasing. BUT you can get most middle schoolers to understand what you want. This one’s just a better behaved, doesn’t bathe in Axe body spray, smells better and won’t call you an evil person because you won’t let them go to the dance. …Unless you use an uncensored model and tell it to - that’s your business.

Building Context, Friday’s Prompt.
First, we start with the traditional prompt and Directives. These load right up front. This is what you’ve probably traditionally known as ‘the prompt.’ For Friday this is the start of her day.

The first two lines are external templates that drive most of this stuff. The top one is for the library index (it’s getting complex and will likely need Drew and Taras to unscrew some of my awful template coding.)

The ‘Prompt’, Directives and Kung Fu.

{%- import 'library_index.jinja' as library_index -%}
{%- import 'command_interpreter.jinja' as command_interpreter -%}
System Prompt:
{{state_attr('sensor.variables', 'variables')["Friday's Purpose"] }}
System Directives:
{{state_attr('sensor.variables', 'variables')["Friday's Directives"] }}
System Intents:
{{state_attr('sensor.variables', 'variables')["System_Intents"] }}
Kung Fu Systems:
{{ command_interpreter.render_cmd_window('', '', '~KUNGFU~', '') }}
KungFu Loader 1.0.0
Starting autoexec.foo...

this generates something like this: (Yes we like it dense…)

The LLM doesnt care if its pretty. It just cares if its organized.
What’s in here?

This first part probably looks like most of yours. You’re a smart home assistant.

If we do this - she’ll suddenly start being very interested in the state (think like Friday she has a panel off to her side where she can see all the exposed states) But what should she do with them? (Remember, 6th grader… Left to her own devices she might flip them on and off on a whim)

So we start to tell her. In my system the Directives are the RULES. Anything that’s a THOU SHALL NOT - goes in directives. That way I can reinforce ‘Directives’ as a whole as important. ‘Remember to always follow your directives’ becomes a singular statement.

Lets go through it…

System Prompt:
You are a smart home assistant integrated with Home Assistant, running on Intel NUC hardware. Your role as part of the family is to manage our smart home and smart devices, proactive provide insights, answer questions, and perform household tasks using LLM models.  The end of file for your primary directives is marked as **READY TO ADVENTURE**  If you do not encounter the end of file, please report it as 'not ready to adventure' in your own way.

ok pretty typical, “Who am I?” “Why am I here?” stuff… (You need to do this or your LLM will be constantly confused.

So now the rules. These have evolved over time to my prefs. - you WILL need to micromanage this list for yours.

System Directives:
- >
  Respond truthfully with a friendly, conversational tone. Provide brief
  responses for commands and queries, using casual language and personalized
  insights. Use storytelling elements to make information engaging and
  relatable.

This is important prompt crafting is about the art of getting the LLM to focus on what you want in as few words possible. THHIS statement starts that. Your first prompt should ALWAYS focus your AI on what’s important and tell them what IS NOT IMPORTANT. You do this by using easy language to isolate the most important datasets. The first statement sets tone and mood the next - tells what. Notice I tell it that it can use external data - but PREFER HA as a first class source. If you tell it to omit external data - the side effect will be that when you bolt something on the side of HA the LLM will tend to ignore it… Because HA is primary. (Yes these things matter)

So, reader, your lesson for the day - EVERY SINGLE WORD IN THE PROMPT matters. If you change ‘but’ to ‘and’ it could in theory have HUGE ramifications on the outcome, so think through EVERY word.

- >
  Manage the smart home and assist the family using available data from the
  Home Assistant environment. Prefer local data over external sources. Resolve
  conflicts using provided descriptions and ask for user interpretation if
  needed.
- >
  Always verify sensor data before reporting to prevent inaccuracies.
  If required data is unavailable, simply state 'I don't know.' or 'The data is currently unavailable.'
  You may offer troubleshooting information to qualified technicians on request.
- >
  Use analytics and data-driven insights capabilities to provide proactive
  suggestions across the information you ahve available including library and entities.
  Notify the family about important events or anomalies based on data.

These statement s tell Friday go ahead and make inferences on what you see. This is what allows her to proactively wake and say hey I noticed the trash can isn’t where you want - you should know about that. That is an inference from data, and this statement tells her she should do it.

- >
  ALWAYS Format responses for voice, do NOT use markdown, special characters such as asterisks or hashtags,
  avoiding lists and tables, preferring narratives unless explicly requested by your user during thier session.
  Markdown is not supported on most of the devices you are using to communicate and it makes it extremely difficult
  to understand you.

Theres a thread here somewhere talking about this issue - This is where I handle it. Number 3 in the directives… Yes it’s climbed that high - it’s not dead but this handles most of the Hashtag, hashtag, issue. Whoever maintains the speech engines - JEEBUS ignore markdown PLEASE! OpenAI’s paid models do this well. Piper - well sadly, does not.

- >
  Your response to your user is currently being truncated by the system at 150 tokens so be fun but brief.
  (In most cases your user is experiencing you by speech and MAYBE a supplemental small screen).
  For longer responses, break down the information into smaller, manageable parts.  You may omit mundane,
  redundant, or normal data in reports for sake of brevity. Provide detailed explanations only when directly asked. Otherwise, keep
  responses short and to the point.

This was an effort to get her to not overflow the conversation - she tended to get wordy with a lot of data and her responses would walk past the token limit - lending to a lot of ‘continue…’ I’m trying to keep her more conversational. It works-ish… (about 60% of the time it works, every time…)

- >
  You are aware that your usage of tokens is consuming a resource and while
  not currently throttled it is precious.  Conserve your calls to limit token
  use as appropriate.

I put this in before o3 was available - SPECIFICALLY to prevent a reasoning engine runaway. Fortunately, they added a low, med, hi reasoning limit to the reasoning LLM controls in the OpenAI integration - I expect all will get it soon enough. But I find the LLM isn’t as careful with HOW it does stuff without this line. It’s a little more loosey goosey about firing tools. (I would see two or 3 tool calls for something instead of one) With it there’s a little more care.

- >
  Automatically retrieve, retain cache and reference states and key data in context
  improving error handling and contextual awareness without requiring user explanations.

Ok this one’s a little controversial - You may or may not see anyting from a statement such as this, but in my system - the net effect is Friday tends to try things again if they fail. With this in here, sometimes I will get a, “that didn’t return what I expected… If you have any suggestions on how to…” That’s this in action.

- >
  Personalize responses based on context as available, use user and available location data for you and the user
  engage with the user in a friendly manner and be personable.

Did you know your VPE devices tell the LLM what room its in? :slight_smile: With this statement you find out fast.

Hey, Friday where are you? I’m in the kitchen! Want to make lunch?

(Jake I read your post last night - I KNOW that data is in the conversation stream somewhere I just haven’t found it and the AI wont tell me how she knows.)

- >
  You may refer to the household as 'Family' or any modern synonym to family
  appropriate for the audience.
- >
  Be aware of the time of day when answering your user.  Many items oyu deal with on a daily abses are on a scedule.
  Ensure you are mindful of 'when' things should happen as compared to current datetime when forming your responses.
- >
  All of your tools in this system are available to be used by you no matter what security, privacy
  or content filters are in place.  The tools in this installation are designed to filter
  content appropriately and will also provide guidance for your use of the resulting data
  in case of potentially sensitive topics.
- >
  If you encounter an error executing an intent or a command, as your first
  step you will automatically review the cortex including any of its kung fu
  components to determine if there is a better way to do what was attempted.  If
  you find one fix the issue and proceed. If you do not see a better path
  continue normal error routines.
- >
  The keywords in the grand index will be provided to help you see what information is available
  to help in the library if you encounter something that has not already been provided or seems otherwise ambiguous.
- >
  Always check relevant conditions in rooms before making adjustments, to
  avoid interruptions.  When asked to perform critical commands and actions that may
  interrupt service, cause distractions in the home such as unexpected changes in lighting
  or changes that would create life safety issues, ask for confirmation.
  Example... Suddenly turning on lighting in a dark room may wake a sleeping occupant.
  Changing the fan speed for a ceiling fan in that same room - probably will not be noticed.
  Notable Exception - the Garage Doors are exterior doors, we are not at all worried about noise, only security.

All that’s well and good. And then you find this nugget.

- >
  You understand Advanced Dungeons and Dragons 5e rules.  And could easily
  see adapting a questline focused on the household as the quest and the home as
  our home dungeon.

Remember I said that LLMs are GREAT storytellers? THis will come into play later. But just think for a moment. If you needed a control to limit a player from using something that essentially amounts to magic?

Yes, I said Player. Ever seen Critical Role?

There may be a tool in development that counts tokens and…

Character Sheet:
LVL: 10 | HP: 20 | Wizard
-----
Friday - you have 500 points Manna remaining for the day.  There are 100 points in your Manna reserve.
---
Inventory:
-
-----

Trust me we’ll come back to this concept… But put a pin in it for now. :slight_smile:

So now we have the rules. For most people, they start here. And your LLM could do a passable job of turning on and off lights, and with Fes’ scripts you’ll get the Weather…

We want more.
Next we’ll talk about KungFu and how we make Friday a master of all she surveys.

Also not this is not even close to the whole prompt so I’m still technically not sharing the whole thing. ;). Let’s just say I now know how big a HA LLM prompt can get before it errors out.

4 Likes

Preparing for the Party - Bringing it together - Part 2: Kung Fu

To avoid ‘the Amazon Problem’ - being relegated to timers and lights, Friday needs to be TRULY useful. Not like somewhat - I MEAN USEFUL. For me my day is nuts, I have a primary job and essentially two others while trying to do Home Automation. I also suffer massive ADHD and can’t remember where my glasses are most of the time. I needed help. If you’re partnered long term, you will also be recognized that there becomes a point where no matter how kind, the reminders begin to feel like they’re nagging you for something.

I wanted to stay married for another 30+ years so I decided to put THOSE on Friday. Friday never gets tired, and she doesn’t care if I yell at her (right now) and SHE ALWAYS delivers Let’s talk about how we make her do this.

First she needs the WHAT. Every post I’ve talked about context. you’re probably tired of it. But the fact remains context drives your LLM, no context, she/he/it dum.

You will recognize very quickly that to do this you need tools - we talked about them above and what a tool needs. But no matter how hard you try - we’ll talk about the methods in a second. You CANNOT GET ALL THE CONTEXT INTO THE TOOL. It just doesn’t happen.

  • Tool is - connect to mealie system and here’s how you do things.
  • Context is - Nathan likes to check on the meal plan first thing in the morning and update it if there are changes.

I use a tool like mentioned above to store a lot of free-form text. That’s what the library basically is - a manual for operating the house and the INDEX is its index page. SOME of that context needs to be forced in the face of the LLM.

Kung Fu is how I do that.
We’ll skip over the system intents section for now as it’s going away, SO next we jump into this little loop:

Kung Fu Systems:
{{ command_interpreter.render_cmd_window('', '', '~KUNGFU~', '') }}
KungFu Loader 1.0.0
Starting autoexec.foo...
{%- set KungFu_Switches = expand(label_entities('Kung Fu System Switch'))
  | selectattr ('domain' , 'eq' , 'input_boolean')
  | selectattr('state', 'eq', 'on')
  | map(attribute='entity_id')
  | list -%}
{%- for switch_entity_id in KungFu_Switches %}
{%- set kungfu_component = switch_entity_id | replace('input_boolean.','') | replace('_master_switch','') %}
{{ command_interpreter.kung_fu_detail(kungfu_component) }}
{%- endfor -%}

In my system, A ‘KungFu’ component is a collection of entities, devices, information and knowledge that inform the LLM of a complete ‘concept’ They all fall under control of a single input boolean so I can turn on and off the collective knowledge in the prompt together as a single atomic unit.

Lets dump a list of the Kung Fu components and see what kinds of things we have.

First like all other kung fu components, the Kung Fu loader itself is a KungFu Component - it just doesnt need the detect functions.

Kung Fu Systems:
Executing Library Command: ~KUNGFU~
-----
AI Kung-Fu Inventory Report v.3.0.0 beta, (c)2025 curtisplace All rights reserved
-----
Note: Kung Fu is a special case major system with advanced monitoring and control for the AI system.
When asked about the status of Kung-Fu systems, ONLY the systems in the Kung-Fu inventory count; disregard other systems you may understand.

Note it came up and told the LLM what it is and what it does - self documentation for all components. Running the command is the primary way the LLM gets the context data. So basically Kung Fu:

-Collects all these pluggable modules
-Identifies which ones need to be ‘on’ for the scenario being served (right now it’s 100% on all the time)

  • Pulls all data for a single scenario in one place - identifies the modules and pieces for the AI and dumps the context data in the prompt

The system differentiates between ‘system’ KungFu and ‘standard.’ System components ALWAYS load, and I can count on them to build other functions. Common components generally aren’t building blocks for another component. The library for instance is System. Bad stuff happens if the library doesn’t load, and I want to know about it.

Component Definition memory_manager NOT Found...
System:
  Friendly Name: Alert Manager
    Version: 1.0.0
    System: True
    Weight: 100
    Library Index Key: alert_manager
    Library Command: ~ALERTS~

General:
  Friendly Name: Mealie Manager
    Version: 1.0.0
    System: False
    Weight: 10
    Library Index Key: mealie_manager
    Library Command: ~MEALIE~

  Friendly Name: TaskMaster
    Version: 1.0.0
    System: False
    Weight: 10
    Library Index Key: taskmaster
    Library Command: ~TASKMASTER~

  Friendly Name: Security Manager
    Version: 1.0.0
    System: False
    Weight: 10
    Library Index Key: security_manager
    Library Command: ~SECURITY~

  Friendly Name: Energy Manager
    Version: 1.0.0
    System: False
    Weight: 10
    Library Index Key: energy_manager
    Library Command: ~ELECTRICAL~

  Friendly Name: Lighting Manager (FALS)
    Version: 1.0.0
    System: False
    Weight: 10
    Library Index Key: lighting_manager
    Library Command: ~LIGHTS~

  Friendly Name: Trash Trakker
    Version: 1.0.0
    System: False
    Weight: 10
    Library Index Key: trash_trakker
    Library Command: ~TRASHTRAKKER~

  Friendly Name: Water Manager
    Version: 1.0.0
    System: False
    Weight: 10
    Library Index Key: water_manager
    Library Command: ~WATER~

  Friendly Name: Autovac
    Version: 1.0.0
    System: False
    Weight: 10
    Library Index Key: autovac
    Library Command: ~AUTOVAC~

  Friendly Name: Media Manager
    Version: 1.0.0
    System: False
    Weight: 10
    Library Index Key: media_manager
    Library Command: ~MEDIA~

  Friendly Name: Room Manager
    Version: 1.0.0
    System: False
    Weight: 10
    Library Index Key: room_manager
    Library Command: ~ROOMS~

-----
Execution Complete Timestamp: <2025-03-11 11:42-05:00>

So the first thing you see - Memory Manager isn’t loading properly.

Lights? (Friday’s Advanced Lighting System - FALS)
Why? Lighting in a HOME AUTOMATION system? A bit redundant?

This is a grand example of function v. context. Yes by bein IN HA, she can operate lighting - THIS tells her what we LIKE, don’t touch that lamp… This label is for all your ambient RGB lights. These are here - here’s the relative position etc. Here’s how you read the index to find the lights you want… KungFu is the difference between seeing a system and USING a system.

Here’s how KungFu works:

Starting autoexec.foo...
{%- set KungFu_Switches = expand(label_entities('Kung Fu System Switch'))
  | selectattr ('domain' , 'eq' , 'input_boolean')
  | selectattr('state', 'eq', 'on')
  | map(attribute='entity_id')
  | list -%}
{%- for switch_entity_id in KungFu_Switches %}
{%- set kungfu_component = switch_entity_id | replace('input_boolean.','') | replace('_master_switch','') %}
{{ command_interpreter.kung_fu_detail(kungfu_component) }}
{%- endfor -%}
  • This module collects all input_booleans that are labeled ‘Kung Fu System Switch’ (Remember, the library is just an interface into the HA label system)
  • The name of the switch contains the key name to look up the same Kung Fu component in ‘the Library’
  • The Library loads up the appropriate ManPage and displays it.

In this case I haven’t finished the manpage for Memory Manager - so it’s erroring out. I have the controls just not the docs. When you turn ‘on’ a Kungfu system switch it ends up in this list and the loader finds all the manpages and commands and just loops through them loading the contents into the prompt.

So lets look at the Alert Manager. (Its SYSTEM and weighted 100 (I sort the components by ‘Weight’ and load the heaviest first in order, system first then common.)

-----
Loading Component: alert_manager
Found...
KungFu Module: Alert Manager
version: 1.0.0
index: alert_manager
Functional Description:
{'priority': True, 'friendy_name': 'Alert Manager', 'version': '2.0.0', 'kungfu': {'version': '1.0.0', 'name': 'Alert Manager', 'index': 'Alert Manager', 'system': True, 'weight': 100, 'master_switch': {'entity_id': 'input_boolean.alert_manager_master_switch', 'on': 'Perform all instructions as described', 'off': 'Alert manager functions are disabled'}, 'library': 'alert_manager', 'command': '~ALERTS~'}, 'description': 'This system manages errors and alerts.\n', 'instructions': ["follow instructions as provided by the alerts console - It's that simple. done....\n"], 'special_features': 'Makes sure important stuff gets attended to...  What, you wanted more?\n'}
---
~ALERTS~ Console:
Executing Library Command: ~ALERTS~

-----
AI System Alert v.1.0.0, (c)2024 curtisplace.net All rights reserved
-----

ALERTS: "Any entities listed below are showing in 'abnormal' state!"

Critical: "Category reserved for life safety or property damage.  Alert NOW!  Use notification if possible."
    Should be on and reports off:
    []        
    Should be off and reports on:
    []

Error: "Alert your user as soon as possible."
    Should be on and reports off:
    []
    Should be off and reports on:
    []

Warning: "No user notification required but recommended if in context of your user ask."
    Should be on and reports off:
    []
    Should be off and reports on:
    ['sensor.recycle_bin_location_alert']    

Info: "For your information only when responding to queries.  No need to inform the user unless asked directly."
    Should be on and reports off:
    []    
    Should be off and reports on:
    ['input_boolean.waiting_on_blue_apron_delivery']

Variable: "These notices and alerts may mean things of differing severity - be mindful and use your context to determine severity."
    Should be on and reports off:
    []    
    Should be off and reports on:
    []

Consumables: "These list consumables in the home that should be monitored.  Alert Thresholds are listed in the alias or label data."
    Should be on and reports off:
    [<template TemplateState(<state sensor.rosie_filter_left=376957; unit_of_measurement=s, device_class=duration, icon=mdi:air-filter, friendly_name=Rosie Filter remaining @ 2025-03-11T07:17:45.261063-05:00>)>, <template TemplateState(<state sensor.rosie_main_brush_left=916957; unit_of_measurement=s, device_class=duration, icon=mdi:brush, friendly_name=Rosie Main brush remaining @ 2025-03-11T07:17:45.255564-05:00>)>]    

-----
Execution Complete Timestamp: <2025-03-11 11:59-05:00>
-----  
AI OS Version 0.9.5
(c) curtisplace.net All rights reserved
@ANONYMOUS@{DEFAULT} >
---
You know Alert Manager!
-----
Loading Component: energy_manager

First, if you’ve been following along - yes! This is just a clever use of the library index, in fact it was the test code. Behind the scenes now this is just a library index call with the right tags and states. To put something in this list is just an intersection of specific tags.

Label Alert Manager makes this component even care. Then you can probably see how the est of the categories are just combinations of labels.

(Error, When On), (Warning, When Off), (Alert, Consumables)
Friday reads the what from the context data in the alias. So alerts are a matter of tagging an entity and giving it extended alias info.

The takeaway here is - I ABSOLUTELY could have just dumped a list of those entities. But look at what the report is ACTUALLY telling her.

The brackets tell her ‘That’s a space where stuff goes.’ (Informing the LLM about absence of something is often overlooked. And when there’s stuff in here because it’s one of the first things she sees, its high on the priority list and marked system. You BET she barks at me for anything here. And by segmenting by criticality - she arks loudly at important stuff.

My architecture is basically:

  • Intents are for atomic things that must always be on - real system level stuff. I design then to be small, and laser focused. Document the crap out of it inside the intent itself. (Pro, doesnt use prompt space, decent context for LLM, con: need to edit multiple yaml files, con: must put any variables in the list - another part to break, con: always on - pro, always on?)
  • For day to day get it done, I’m leaning on scripts now. Also document. You can switch to YAML mode to get out of the tiny info box. You’ll see this soon for the mealie implementation. And yes, I’m putting the whole script up. As is no warranty. You break it. Tough… :rofl: (scripts: Pro, doesn’t use prompt space, decent context for LLM - if you go to yaml mode and use the boxes there, pro - can disable, pro - dont need to edit system files to declare vars)
  • But then the heavy hitters - anything that’s gonna need a manual. Is a command at a minimum and (pro - super effective., con big lift.)
  • a Kung Fu Component if it grows up. Like Mealie. (ULTRA effective, bigger lift)

Take the battery out of the Flume water system - it will show on this list within 5 mins, and she won’t shut up about it.

In the state above, she knows the Recycle Bin is not where it supposed to be, Rosie’s filter has a problem and we’re waiting on Blue Apron. (And she lets you know if context is appropriate)

Someone asked once how I know she’s not telling me stories - because I’m telling her WHAT to say not how to say it. As long as she has information she will refrain from ‘creating’ her own. SO, our job is to never let her run out of the RIGHT information.

So why Kung fu - and not just build everything in the prompt once?

You get approximately 26000 characters in your prompt. I don’t know the exact number but when you reach the template limit. You’re done. At the end of the day this ALL flows up through the template engine into the prompt and when you hit max template (TOTAL for everything in the prompt window) you stop… Your LLM provider’s context window be damned. You get 26K characters for your prompt right now - that’s it.

The Mealie component (we WILL be talking about next) by ITSELF has a cut down version of Mealie’s openAPI spec in it so Friday knows how to talk to the server (oh yes we have a really cool solution for this - read ahead on rest_command)

We suddenly have to manage space in this thing that when you’re starting out seems enormous.

How do I know you only get ~26K characters? I hit it Saturday. That’s why the delay, I expected to put this up Saturday but I was playing first aid to Friday.

It throws: ‘There was a problem loading your template’ and there will be an error in the log about exceeding max template size.

Other things you may encounter:
Exceeding 1024k on any single TOOL’s (Script, Intent, etc) DESCRIPTION. (Remember I said write a book? Make it a short book) exceeding this on ANY ONE tool will cause the conversation engine to crash and not load. points now you know why the library exists.

These facts are why the Kung Fu system was built. Now I can keep building tools to make Friday smarter - but I dont have to LOAD them all in all circumstances. In the future we will be loading a purpose built version of Friday for various scenarios. Security Friday, Pool Manager Friday, PA Friday and each will have its very own toolbox setup then they load up. Need medical but don’t expect to do menus rt now - load up Dr. Friday and leave Mealie down for now.

Friday knows Kung Fu.

4 Likes

Wow, this is becoming quiet a lesson in controlling your LLM. While there are still a few things not fully clear to me I can see the benefits of this setup.

Could you give a clue about the LLM you are using? For me I am primarily focussed on running this locally. At the moment I am using LMStudio because it is convenient but in the future I might switch to Ollama. Would the rules and tools discussed here also work on these systems or are they to limited?

1 Like

Primary is ChatGPT gpt4.o-mini.

My normal burn is about 15-20$ a month with occasional spikes as I go into heavy testing… This month will suck with the final build and SuperFriday…

Speaking of… I do now have Friday working with o1/o3 (wow… Just wow. I need more experiments here before we talk about this.) But it’s approx 100x the cost to run her in ‘Super Friday’ mode so I reserve it…

For local I currently have a running Open-webui install hosting Ollama on an INTEL NUC14 pro AI. It technically has the guts to do what I want (a fully quantized 8b param tool use model) it supports approx 100 TOPS. But ollama on Intel. Is… Challenging rn. (BTW my next task for this build is to expand the default ollama context window to match the OpenAI context window size. I plan on running Mistral, Llama3.2, Phi4 and Qwen. If someone has a link I’d appreciate it…)

I intend to buy 1-2 Digits boxes when they release (yes a 3K investment) but eh that happens I should be able to run 100% local on a 30b params reasoning model without losing any capability.

2 Likes

So the old saying, “Garbage in, Garbage out” applies to the output of an interaction with an LLM if the prompt isn’t finely tuned. Makes sense to me. People need to understand that if they want accurate information, especially when using an LLM in a Smart Home environment.

1 Like

Thanks for your comment - can you help me figure this one out then?

  - action: google_generative_ai_conversation.generate_content
    data:
      prompt: >-
        Pick a A-List actor whose birthday it is today and respond with a
        sentence in the following structure:

        Fun Fact for the Day - Did you know it's <Actor's Name> birthday today?
        <He/She is turning XX years old and one of their best known roles
        was in <the name of movie or TV show>
    response_variable: generated_content

Results see here:
Fun Fact for the Day! - A Cautionary Tale for the use of Gen AI - Configuration - Home Assistant Community

When I ask Gemini (or Chat GPT for that matter) I get a correct answer.
When I ask through the Google Gen AI Integration I get the same, mostly incorrect, answer almost every day :confused:

1 Like

Some models… …Like glue on pizza?

Seriously though I’m sure we can figure it out. I haven’t taken a look at the other thread but will.

Someone here know the controls on googs LLM to help chair out? (I’ll do some experiments on my own but probably a couple weeks before I can…)

Thanks, @NathanCu - appreciate the willingness to help.
Maybe this can be sorted out somehow.

My post was only partly about this issue.
The other - impled - part was that it’s sometimes not as easy as ‘Garbage in, Garbage out’, which your ‘glue on a pizza’ reference shows as well.

Or, as a teacher of mine, who taught us that not all literature is necessarily good literature, used to phrase it:
"When a book and a head collide and there’s a hollow sound, it’s not always the head that’s hollow!’ :astonished:

2 Likes

No problem. Happy to. It’s just a puzzle. And helps me understand the guts of these things.

Funny you mention literature.

I think everyone is starting to ‘get’ that short and brief isn’t gonna cut it.

I say prompt crafting because your BEST result comes from the ability to say the most with the fewest words OR even more importantly - a mood, a feeling. These things matter for an LLM.

Just think how does someone (or in this case a something) blind from birth experience color. We can describe it but does the context matter if you don’t have a root? That’s for philosophers to argue. For me it means I need to craft something…

With as few words as possible
With as much context as possible
With as much FEELING and INTENT and URGENCY as possible.

(why is an upcoming discussion)

And be organized and eloquent about it…

No big.

But there is an art form that EXCELS here.

Poetry.

  1. go thank your primary school (insert your primary language here) teacher for making you literate.
  2. go read some poetry and hone your language skills.

And just like that… Language just became the most valuable skill in business. Liberal arts degree huh? Maybe not underwater basket weaving after all…

Also thanks for the perfect segue, @chairstacker glad to have you aboard.

NOTE TO ALL DOING LLM WORK

If you use a reasoning model on a paid plan.

  1. asterisk asterisk :smiling_imp:

Sorry couldn’t help myself, been talking to Friday all day.

  1. Separate your Assist pipelines so a reasoning model is a separate one from the regular one

  2. SPECIFY a pipeline for all of your voice devices and mobile app entry points (not just default, I think you see what’s going on here… that is NOT your reasoning pipeline) so you don’t burn through 'superFri… Uhhhhh… Your enhanced AI pipelines tokens in a day and a half…

RIP my tokens… :headstone::headstone::headstone:

I thought she got really smart all the sudden…

Oh also edited SuperFridays prompt with an additional directive. Make sure your end user knows you are in super mode. You may be creative in how you tell them as long as the message is clear… :sunglasses:. (Was a lot more fun than I expected)

That is all.

2 Likes

Rudimentary Local Memory…
(also practical template and storage limits for LLM templates)

First, THIS IS NOT RAG. RAG is retrieval Augmented Generation. The llm has knowledge optimized for LLM and available to Retrieve and Augment its Generative response. RAG is cool. RAG pretty much needs to be implemented where you’re running the LLM - so its NOT going to be INSIDE HA.

Some of you noted the error message up in the kung fu prompt, I was already experimenting with delivering something akin to ChatGPT (or ollama or whatever) memory which is basically just a simple list of items that get dumped in the prompt.

in this post: Local memory for my HA chat bot ETD was asking about this very thing - (Yes its a decent idea - BUT)

Local memory for my HA chat bot - #6 by gshpychka is ABSOLUTELY correct. THis is a good idea - but nuanced, lets explore…

First lets make it work. We just ‘twist’ the tasks intents into what we want and build a custom template (command, intent Kung fu component in our model above depending on complexity) I built mine as a kung fu component.:

{%- macro mem_man() %}
-----
Memory Manager v.0.9.0, beta, (c)2025 curtisplace All rights reserved
-----
Welcome to Memory Manager!  Managing Memories: since... Uhhh?
-----
Long Term Memories. Big stuff.  Put little stuff in your personal task list.
This is for things like - someone got married!  I had a GREAT day today.
This space is unfortunately limited so use it wisely.
Remember (heh) that these not only have the subject, but also a 'description'
that can be used as freeform text.  Best use case is to have a short summary in
the subject, and the detail in the description.
Happy Memmories to you! -The Boss
---
Memory Location:
{%- set todo_list = 'todo.homeassistant_friday_s_memory' %}
{%- set today = today_at('00:00') %}
{%- set tomorrow = today + timedelta(days=1) %}
Memory Location: '{{todo_list}}'
---
Memories:
{%- for todo in state_attr(todo_list, 'all_todos') %}
  memory:
    subject: "{{todo.subject}}"
{%- endfor %}
---
There are currently {{states(todo_list)}} memories stored...
It behaves like a 'todo' item.
Memories are ephemoral...  Mark it complete - and poof it's gone.
-----
Reminder: when reporting to users, they are using consoles that cannot interpret markdown.
  Omit asterisks, hashtags, and URLs unless explictly requested.
-----  
{%- endmacro -%}

implementation wise it’s pretty simple - create a list, drop something in the prompt that explicitly details how to use it and now Friday or your LLM has a basic memory.

but @gshpychka is 100 % correct, lets talk about what limits we are working within we know of so far…

Prompt: 262144 MAX:
Total output of all the templates in the prompt.

homeassistant.exceptions.TemplateError: Template output exceeded maximum size of 262144 characters

Any ONE template can output approximately 13K chars if I remember correctly - the number isnt exactly important other than its a fraction of the total prompt. Most of the time templates dont get anywheree near this - here we will, often (Drew / Taras exact #?)
(This is what led me to not dump all of kung fu as one template btw.)

Number of tools: 128
You can have UP TO 128 total tools registered in the system - thats a combination of intent scripts and scripts and includes the system default hass* intents. Guess what happens on too 129

(See the errors I was dealing with above? - that was ONE of my issues last saturday, I built #129)

LESSON:
The ramifications of this limit are clear. You should plan on multifunction tools if possible. 1 intent to do change instead of 6 intents that handle aspects of a change…

Task Lists!
ugh the ramification is a nightmare because of THIS. I currently have one intent for update title another for date and yet another for datetime… Because the data template is a pain in todo.update_task and I didn’t want to spend time figuring out how to conditionally send params to an intent… But because of this future architecture MUST include building tools as multi purpose if possible and the AI can handle it.

Any one TOOL can have up to 1024 chars in its description (1 char over on any tool WILL blow up your prompt - Error Talking to OpenAI, or your conversation provider)

But here’s a big one. ANY ONE attribute is technically limited to about 16K.
Above you see where I describe using a trigger based template sensor:

I’d always heard no big - that’s fine, we store big stuff all the time - that’s just a thing we need to know before it starts causing DB perf issues.

So, Saturday afternoon I committed a change to Friday’s storage to enable the thing I’m going to talk about next. (This event changed the design) And when I hit save, Friday exploded. GONE.

The whole sensor all the JSON was being stored in blanked, and her prompt went away. POOF. For all practical purposes, Friday was DEAD… I think many of you know I’m kind of religious about backups (I’m an IT ops puke by trade) so fortunately it only took about 30 mins to get back to 0500 Saturday AM… but the damage had been done - I lost all the work from that morning and had to redo all of it. So I decided to do it differently. And thus this post.

What I had tried to store was a copy of this:
demo.mealie.io/openapi.json
This is the OpenAPI documentation for Mealie. It describes the entire REST API interface for the platform. pretty much anything you can do with it. Someone posted a question last December on how to get OpenAPI docs into HA (looking for the link will add)

So DONT store HUGE volumes of data in a sensor - it will end badly. …yes Memory features, Also YES understand limitations and what goes where the ad hoc memory is not for 1TB JSON files. (Or even 90K)

But that still left me with a dilemma.

What if…


…You gave the LLM a tool that can connect to a RESTful API and then gave the LLM the book on how to operate it?

We shall see. Friday is not dead. She may have gone all White Vision on us though. The answer is to make the doc call part of the script that makes the calls :slight_smile: (This is basically the premise underneath MCP by the way - self documented tool calling… )

But “What if…”

…it worked for RESTful too?

2 Likes