mirror of
https://github.com/andrewyng/openworker.git
synced 2026-09-13 15:50:02 +00:00
coworker picker: 'Use temporary folder' copy; retire Chat persona
Chat ships disabled+unsurfaced (Coworker covers quick Q&A); recoverable from Settings.
This commit is contained in:
@@ -50,6 +50,10 @@ class PersonaEntry:
|
||||
default_surfaced: bool = (
|
||||
True # whether it shows in the picker before any user choice
|
||||
)
|
||||
# Whether it ships enabled before any user choice. Builtins default on (UX-029: the
|
||||
# composer picker is their front door) — except retired ones (Chat: Coworker covers
|
||||
# quick Q&A). Installed third-party personas always start disabled pending consent.
|
||||
default_enabled: bool = True
|
||||
_builder: Optional[Callable[[], Agent]] = None
|
||||
manifest: Optional[PersonaManifest] = None
|
||||
|
||||
@@ -101,6 +105,7 @@ class PersonaRegistry:
|
||||
tools,
|
||||
workspace="deliverable",
|
||||
default_surfaced=True,
|
||||
default_enabled=True,
|
||||
) -> None:
|
||||
self._entries[id] = PersonaEntry(
|
||||
id=id,
|
||||
@@ -113,13 +118,14 @@ class PersonaRegistry:
|
||||
workspace=workspace,
|
||||
tools=list(tools),
|
||||
default_surfaced=default_surfaced,
|
||||
default_enabled=default_enabled,
|
||||
_builder=builder,
|
||||
)
|
||||
|
||||
def _load_builtin(self, builtin_dir: Optional[str | Path]) -> None:
|
||||
# Core surfaces keep their exact prompts via the existing builders. Cowork (the default)
|
||||
# leads; Chat is hidden from the picker by default (Cowork covers quick Q&A) — recoverable
|
||||
# from the Personas tab.
|
||||
# leads; Chat is RETIRED (owner call 2026-08-11: Coworker covers quick Q&A) — it ships
|
||||
# disabled and unsurfaced, recoverable from Settings ▸ Coworkers.
|
||||
self._register_builder(
|
||||
"cowork",
|
||||
"OpenWorker",
|
||||
@@ -153,6 +159,7 @@ class PersonaRegistry:
|
||||
[],
|
||||
workspace="none",
|
||||
default_surfaced=False,
|
||||
default_enabled=False,
|
||||
)
|
||||
# Markdown-backed built-ins (Ops, …) — dogfood the manifest path.
|
||||
d = Path(builtin_dir) if builtin_dir else Path(__file__).parent / "builtin"
|
||||
@@ -219,15 +226,16 @@ class PersonaRegistry:
|
||||
return self._entries.get(persona_id)
|
||||
|
||||
def is_enabled(self, persona_id: str) -> bool:
|
||||
# Explicit state (either way) always wins. Absent a user choice, BUILT-IN personas
|
||||
# ship enabled — the composer picker is their front door (UX-029, supersedes the
|
||||
# 2026-07-09 Coworker-only default that fit the old hidden ▾ menu). Installed
|
||||
# third-party personas stay disabled until the user consents from the risk screen.
|
||||
# Explicit state (either way) always wins. Absent a user choice, the entry's
|
||||
# default applies: builtins ship enabled — the composer picker is their front door
|
||||
# (UX-029, supersedes the 2026-07-09 Coworker-only default that fit the old hidden
|
||||
# ▾ menu) — except retired ones (Chat). Installed third-party personas stay
|
||||
# disabled until the user consents from the risk screen.
|
||||
if persona_id in self._enabled:
|
||||
return bool(self._enabled[persona_id])
|
||||
entry = self._entries.get(persona_id)
|
||||
if entry is not None and entry.builtin:
|
||||
return True
|
||||
return entry.default_enabled
|
||||
return persona_id == self._default or persona_id == DEFAULT_PERSONA_ID
|
||||
|
||||
def is_surfaced(self, persona_id: str) -> bool:
|
||||
|
||||
@@ -57,7 +57,7 @@ const PERSONAS = {
|
||||
personas: [
|
||||
{ id: "cowork", name: "OpenWorker", icon: "cowork", tagline: "Produce a deliverable — research, analysis, scripts", needs_workspace: true, builtin: true, family: "knowledge", workspace: "deliverable", tools: ["files", "search"], enabled: true, surfaced: true, default: true },
|
||||
{ id: "code", name: "Code", icon: "code", tagline: "Work in a codebase — files, git, shell", needs_workspace: true, builtin: true, family: "code", workspace: "git", tools: ["code_files", "git"], enabled: true, surfaced: true, default: false },
|
||||
{ id: "chat", name: "Chat", icon: "chat", tagline: "Quick questions — no workspace", needs_workspace: false, builtin: true, family: "knowledge", workspace: "none", tools: [], enabled: true, surfaced: false, default: false },
|
||||
{ id: "chat", name: "Chat", icon: "chat", tagline: "Quick questions — no workspace", needs_workspace: false, builtin: true, family: "knowledge", workspace: "none", tools: [], enabled: false, surfaced: false, default: false },
|
||||
{ id: "ops", name: "Ops Coworker", icon: "wrench", tagline: "Operate and investigate — runbooks, logs, infrastructure", needs_workspace: true, builtin: true, family: "knowledge", workspace: "deliverable", tools: ["files", "shell"], enabled: true, surfaced: true, default: false },
|
||||
// A non-builtin install (disabled pending consent — invisible to picker specs) so the
|
||||
// Personas page's delete/enable affordances have a target.
|
||||
|
||||
@@ -90,7 +90,7 @@ export function SendFolderDialog({ coworkerName, onPick, onTemp, onCancel }: Pro
|
||||
}}
|
||||
disabled={busy}
|
||||
>
|
||||
Start in a temporary folder
|
||||
Use temporary folder
|
||||
</button>
|
||||
</div>
|
||||
{error && <div className="mt-2 text-[11.5px] text-warnInk">{error}</div>}
|
||||
|
||||
@@ -34,13 +34,15 @@ def test_sidebar_defaults_to_surfaced_builtins(tmp_path):
|
||||
assert "code" not in [e["name"] for e in reg.sidebar()]
|
||||
|
||||
|
||||
def test_chat_hidden_by_default_but_resolvable(tmp_path):
|
||||
def test_chat_retired_by_default_but_resolvable(tmp_path):
|
||||
reg = _reg(tmp_path)
|
||||
assert reg.is_surfaced("chat") is False # default-hidden from the grouped nav
|
||||
assert reg.is_enabled("chat") is True # builtins ship enabled (UX-029)
|
||||
# Chat is retired (owner call 2026-08-11): disabled + unsurfaced out of the box,
|
||||
# unlike the other builtins — Coworker covers quick Q&A.
|
||||
assert reg.is_enabled("chat") is False
|
||||
assert reg.is_surfaced("chat") is False
|
||||
assert reg.agent("chat").name == "chat" # live sessions keep resolving
|
||||
# Surfacing it adds it to the sidebar picker too.
|
||||
reg.set_surfaced("chat", True)
|
||||
# Still recoverable from Settings ▸ Coworkers (enable implies surface).
|
||||
reg.set_enabled("chat", True)
|
||||
assert "chat" in [e["name"] for e in reg.sidebar()]
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user