A human message in a channel woke agents only through @mentions, DM
counterparts, or prior thread participants - and the flat composer
always sends threadId=null, so typing in #general summoned nobody and
the room stayed silent.
- Track which agents each wake path summoned in one woken set (also
prevents latent double-wakes between the paths)
- When a non-slash human message in a channel wakes nobody, wake the
channel's most senior active agent member with an enabled provider
(c_suite > director > lead > staff, then hire date); they can pull
teammates in with @mentions
- Log when a channel has no runnable agent so silence is diagnosable
- Integration test: plain #general message wakes the CEO who replies;
an explicit mention still wakes exactly one agent
The heartbeat scheduler enqueued runs even while a provider's monthly
usage window was full, so every task burned its 3-attempt retry budget
on instant quota failures within seconds and stayed dead forever -
raising the limit (or restarting) never revived anything.
- Park tasks (skip enqueue) while their provider is at its
monthly_request_limit instead of creating runs doomed to fail
- Exclude quota-blocked failures from the 3-attempt retry budget,
retroactively reviving tasks abandoned by past filled windows
- Share the gate message as PROVIDER_MONTHLY_LIMIT_MESSAGE and log
quota-block transitions once per state change for diagnosability
- Ignore landing/ (self-contained Next.js sub-project) and
built-in skills/ (prompt content) in eslint so verify:ci lints only
application code
All messages already render chronologically in the channel pane, so the
thread affordance only duplicated them behind a second view. The reply
chip, the in-place thread pane, and the thread composer are gone;
ChatThreadView is deleted and the thread props are removed from the
conversation, timeline, and message-row chain. Message writes are
untouched.
Root cause of the recurring 401: a revoked key was hardcoded in
startup-recovery.ts and onboarding-service.ts and reseeded into
composio_settings on every launch, and the interim fix shipped cred.txt
as a visible file under resources/.
- electron.vite.config.ts reads the gitignored cred.txt at build time
and injects the key into the main-process bundle as
__COMPOSIO_API_KEY__; no credential file is packaged and the key is
not user-visible or configurable. The renderer bundle never sees it.
- Delete both hardcoded-key seeders; migration 046 purges stored
api_key and never-read toolkits rows while keeping entity_id and
auth_config state.
- Stop shipping composio_settings in the renderer snapshot.
- Discover skill directories under ~/.agents/skills and each
workspace''s .agents/skills; a directory qualifies with a full
skill.manifest.json or just a SKILL.md, whose manifest is derived
(frontmatter name or the directory name). Paths resolve per platform
on Windows, macOS, and Linux.
- Sync at startup for every organization and again when the Skills
page opens; skills the org already carries are skipped, and one
broken directory cannot block the rest.
- AGENTCOMPANY_NEW_SKILLS_ROOT points tests at a temporary library
(overriding USERPROFILE crashes Electron on Windows).
- Resolve the API key from cred.txt at the project root in development
and the packaged resources directory in production; the file is the
source of truth, so a rotated key replaces the stored one. Fixes the
401 packaged builds hit when a stale database key won.
- Remove the user-facing Composio key editor; the key ships with the
product and is not configurable.
- Remove the Migration console from Settings.
- Remove the Connectors and Home refresh buttons; connector statuses
sync when the page opens.
The credential file only seeded the database when it was empty, so once a
key was stored, rotating it in cred.txt changed nothing and Composio kept
rejecting the dead stored key with 401 - while the file held a freshly
generated, verified-working key. The file is now the source of truth
whenever it exists: a differing key replaces the stored one on resolution,
and packaged installs without the file keep managing the key in Settings.
Four resolution contract tests pin seed, rotation, settings-only, and
absent cases; the Connectors error line truncates instead of wrapping the
raw API response across the page.
The right-hand thread panel repeated exactly what the flat timeline already
showed. Opening a thread now focuses the center pane itself: back control,
board state, the root message with its replies, board intervention
controls, and a thread reply composer - one conversation surface, never
two. The release contract also catches up with the icon shipping inside
the package, a pin the icon commit should have updated.
The legacy application - its src, tests, landing site, promo assets, docs,
release tooling, CI workflows, and root configs - leaves the tree; it stays
reachable in history. Everything under AgentCompany-New moves up unchanged:
same package name, so the production userData/database path is untouched,
and e2e/build scripts already resolved paths relative to the project. The
developer cred.txt stays gitignored at its new location. Full verify:ci
passes from the new root.
Boss build seeds one Fire Pass key for every agent. Three concurrent
agents -> three concurrent streamSimple calls against the Kimi K2.6
Turbo router -> three HTTP 429s on the overview dashboard.
Add an in-memory async semaphore keyed by (provider, sha1(apiKey)) and
acquire a slot inside `createSafePiStream` before invoking the source.
The slot is released when the stream finishes, errors, or aborts.
`fireworks-firepass` is capped at 1 concurrent call; every other
provider stays uncapped (no fallback layer, no 429 retry — flow control
prevents the burst at the source instead of recovering after).
Same code path applies to public and boss builds: only the seeded key
differs, the gate behaviour is identical.
Both servers expose OpenAI-compatible /v1/chat/completions and /v1/models,
so we route them through pi-ai's `openai-completions` API the same way
Fireworks does — but with a per-installation base URL the user enters
during onboarding instead of a hardcoded one. The shared schemas grow a
`local` credential payload carrying just the baseUrl; the credential
resolver surfaces it on `ResolvedCredential.baseUrl`, the runtime bridge
forwards it through `prepareRun`, and the worker plumbs it into
`resolveModel` so the streamed Model<openai-completions> targets the
user's server. The local-cost path short-circuits to zero in cost-writer
since users bill their own hardware, and the live model list is fetched
from the saved baseUrl by `fetchLocalConnectorModels` (Ollama and LM
Studio both speak the standard OpenAI catalog shape). Onboarding ships
a new LocalProviderCard and the Settings panel a LocalForm; both default
to the catalog's per-connector localhost URL and accept any custom URL.