A personality belongs to a person
Owner's correction to 1.4.0: a model's character is per (model, person), and only the description and the notes stay instance-wide. Two people talking to one model are not talking to the same personality, and neither can see the other's. The administrator's box becomes the DEFAULT, resolved by `personas.effective` as a fallback and never as a layer -- two personalities at once contradict each other with nothing to say which is losing, which is the reasoning behind "system prompts replace, never stack". `persona_write` takes no argument naming a model or a person; both come from the ToolContext, so it can only write the character it has with whoever it is talking to, and it never touches the default. Impressions move to their own table. Not a `kind` column: 1.4.0 shipped `UNIQUE(model_key, owner_id)`, SQLite cannot alter a constraint and this schema is additive-only, so a discriminator would leave an upgraded instance unable to hold both rows for one pair. That leaves the first MANUAL_STEPS entry this project has had -- the two shapes are indistinguishable, so nothing rewrites them: a repair would be guessing at text that is read back in the first person. TWO BUGS FROM A PHONE `min-width` beats both `width` and `max-width` -- CSS clamps width to max-width and then raises the result to min-width -- so `.canvas` and `.terminal` were 384px wide on every screen narrower than that, their `min(…, 100vw)` cap overruled, and `.inspector` had no cap at all on a width that is a preference draggable to 2400px. None of it scrolled sideways, because all three are `position: fixed` and fixed overflow does not extend the scrollable area -- which is exactly why the 1.1.0 narrow pass reported these pages clean. `min-width: 0` in the overlay query, full width below the phone breakpoint, tablet column kept. And the install button now says why it is absent. Measured against the live instance: the manifest meets every Chrome criterion and the blocker is a certificate from a private CA, so the origin is not trustworthy, the service worker is refused and no install is offered. `base.html` had been swallowing that with an empty catch -- which kept the page working, the reason it was there, and threw away the only evidence. It now records the outcome and `app.js` turns it into a sentence naming the certificate, which is the cause the old hint did not mention. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -270,9 +270,15 @@
|
||||
{{ icon("plus", "icon--sm") }} Install
|
||||
</button>
|
||||
</div>
|
||||
{# Filled by app.js from what actually happened, because every
|
||||
reason the button is absent looks the same from here. The static
|
||||
line below it used to be the only explanation, and it named the
|
||||
one cause that is least likely on a home network. #}
|
||||
<p class="field__hint" data-install-status hidden></p>
|
||||
<p class="field__hint">
|
||||
Only offered over HTTPS or on localhost, and not at all in some
|
||||
browsers. On iOS, use Share → Add to Home Screen.
|
||||
Installing needs a secure connection — HTTPS with a certificate
|
||||
this device trusts, or localhost — and some browsers never offer
|
||||
it. On iOS, use Share → Add to Home Screen.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
@@ -421,15 +427,65 @@
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{# What each model has made of you, in its own words. Shown whether or
|
||||
not any model is still allowed to write one: a model whose
|
||||
permission was taken away has not forgotten, and this is the only
|
||||
place the text can be read or removed. #}
|
||||
{% if reflections %}
|
||||
{# Both halves are shown whether or not any model may still write
|
||||
one: a model whose permission was taken away has not forgotten, and
|
||||
this is the only place either text can be read or removed. #}
|
||||
{% if personalities %}
|
||||
<div class="card">
|
||||
<h2 class="card__title">
|
||||
Who each model is with you
|
||||
<span class="badge">{{ personalities|length }}</span>
|
||||
</h2>
|
||||
<p class="card__lede">
|
||||
A model's character is something it works out with a particular
|
||||
person, so this is yours — somebody else talking to the same model
|
||||
is talking to a different one, and neither of you can see the
|
||||
other's. Delete one and that model starts again from the default
|
||||
its administrator wrote.
|
||||
</p>
|
||||
<ul class="model-list">
|
||||
{% for personality in personalities %}
|
||||
<li class="model-list__item">
|
||||
<div style="min-width: 0">
|
||||
<strong>{{ personality.model_key }}</strong>
|
||||
{% if personality.author == "model" %}
|
||||
<span class="badge badge--leaf">its own words</span>
|
||||
{% endif %}
|
||||
<div class="text-sm">{{ personality.content }}</div>
|
||||
{% if personality.revisions %}
|
||||
<details class="text-xs faint">
|
||||
<summary>{{ personality.revisions|length }} earlier version(s)</summary>
|
||||
<ul>
|
||||
{% for revision in personality.revisions %}
|
||||
<li>
|
||||
{{ revision.created_at.strftime("%Y-%m-%d %H:%M") }} —
|
||||
{{ revision.content }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</details>
|
||||
{% endif %}
|
||||
</div>
|
||||
<form method="post"
|
||||
action="/api/library/personalities/{{ personality.id }}/delete">
|
||||
<button class="btn btn--sm btn--danger" type="submit"
|
||||
data-confirm-button="Reset this model's personality with you?"
|
||||
data-confirm-title="Reset"
|
||||
aria-label="Reset this" title="Reset this">
|
||||
{{ icon("trash", "icon--sm") }}
|
||||
</button>
|
||||
</form>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if impressions %}
|
||||
<div class="card">
|
||||
<h2 class="card__title">
|
||||
What models make of you
|
||||
<span class="badge">{{ reflections|length }}</span>
|
||||
<span class="badge">{{ impressions|length }}</span>
|
||||
</h2>
|
||||
<p class="card__lede">
|
||||
Each model's own impression of how you work, kept by that model and
|
||||
@@ -439,14 +495,14 @@
|
||||
if it has reason to.
|
||||
</p>
|
||||
<ul class="model-list">
|
||||
{% for reflection in reflections %}
|
||||
{% for impression in impressions %}
|
||||
<li class="model-list__item">
|
||||
<div style="min-width: 0">
|
||||
<strong>{{ reflection.model_key }}</strong>
|
||||
<div class="text-sm">{{ reflection.content }}</div>
|
||||
<strong>{{ impression.model_key }}</strong>
|
||||
<div class="text-sm">{{ impression.content }}</div>
|
||||
</div>
|
||||
<form method="post"
|
||||
action="/api/library/reflections/{{ reflection.id }}/delete">
|
||||
action="/api/library/impressions/{{ impression.id }}/delete">
|
||||
<button class="btn btn--sm btn--danger" type="submit"
|
||||
data-confirm-button="Delete what this model makes of you?"
|
||||
data-confirm-title="Delete"
|
||||
|
||||
Reference in New Issue
Block a user