Commit graph

9 commits

Author SHA1 Message Date
Snider
429d1c0897 feat(agent/agentic): RFC foundation — atomic CompleteTask + credit ledger reconcile
Foundation slice for Mantis #841 php/Mod/Agent RFC implementation:

* CompleteTask now wraps in DB::transaction with idempotent credit awards
  and safe current_task_id clearing
* Credits/{Award,GetBalance,GetCreditHistory} updated for agent_id +
  fleet_task_id ledger support and richer balance totals
* GenerateCommand canonical agentic:generate wiring; legacy duplicate
  no longer registered
* Boot wires brain:clean / brain:prune / brain:reindex
* EmbedMemory exits early when memory already indexed
* 3 follow-on fleet migrations reconcile fleet_nodes pointer column,
  fleet_tasks/credit_entries fk/index hygiene, fleet+credit constraints
* 4 foundation tests under php/tests/Feature/Mod/Agent/

php -l clean on all modified files. pest unrunnable in sandbox (no vendor/).

Foundation slice only: remaining model/action parity, full MCP tool/
service sweep, fleet controller auth-context, and 41-tool/45-action
surface left for follow-up tickets.

Co-authored-by: Codex <noreply@openai.com>
Closes tasks.lthn.sh/view.php?id=841
2026-04-25 20:59:38 +01:00
Snider
c616ff1e32 fix(brain): close openbrain audit gaps — org scoping + index cleanup + reindex flags + MCP schemas + circuit layer
Closes the 5 PARTIAL items flagged in docs/AUDIT-openbrain-20260424.md.

- Gap A (org scoping persisted on writes): new migration adds `org`
  nullable+indexed column to brain_memories; BrainMemory fillable;
  RememberKnowledge action forwards org; BrainService::remember
  persists it.

- Gap B (supersede/forget Elastic cleanup): BrainService::forget
  dispatches DeleteFromIndex (handles both Qdrant + Elastic); supersede
  path dispatches cleanup for the old memory id before replacing it.
  DeleteFromIndex itself untouched — already handled both indexes.

- Gap C (brain:reindex flags): --org, --project, --stale (null OR
  >14d old), --dry-run (count+stop), --elastic-only added to the
  artisan command.

- Gap D (MCP schemas expose org): brain_remember, brain_recall,
  brain_list now accept `org` in input schema + forward into
  action/service.

- Gap E (resilience uneven): brain_list now wrapped in
  withCircuitBreaker('brain', ...) matching the pattern used by
  BrainRemember/Recall/Forget. BrainService gains retryableHttp()
  helper — 100/300/900ms exponential backoff, retries only on 5xx +
  connection errors, not on 4xx. Qdrant calls route through it;
  Ollama left alone (EmbedMemory job has its own retry).

Tests (Good/Bad/Ugly per gap):
- Feature/Brain/OrgScopingTest.php
- Feature/Brain/SupersedeForgetIndexCleanupTest.php
- Feature/Brain/ReindexFlagsTest.php
- Feature/Mcp/BrainSchemaOrgTest.php
- Feature/Brain/CircuitBreakerTest.php

php -l clean on all 13 files. Pest binary not in this checkout —
CI path validates the full suite.

Closes tasks.lthn.sh/view.php?id=107

Co-authored-by: Codex <noreply@openai.com>
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-24 08:14:06 +01:00
Snider
4dc5ed8d14 feat(brain): add EmbedMemory job + indexed_at tracking
Implements the async-embedding pipeline's worker side:

- php/Jobs/EmbedMemory.php — Laravel Job that calls BrainService::embed()
  + qdrantUpsert() and sets indexed_at on success
- php/Migrations/…_add_indexed_at_to_brain_memories.php — nullable
  timestamp + index, portable across pgsql/mariadb (hasColumn guard)
- BrainMemory: +indexed_at fillable + datetime cast + PHPDoc
- BrainService: qdrantUpsert() private→public so the Job can use it;
  elasticIndex() stub added (to be implemented by the ES ticket)
- php/tests/Feature/Jobs/EmbedMemoryTest.php — Pest tests for success
  path and Qdrant-failure path

Co-authored-by: Codex <noreply@openai.com>

Closes tasks.lthn.sh/view.php?id=56
2026-04-23 12:47:10 +01:00
Snider
4e190dc7ec fix(brain): Postgres portability for brain connection + migrations
Three related fixes so the brain DB works on Postgres, not just MariaDB:

1. config.php — brain charset/collation was hardcoded to utf8mb4 which
   Postgres rejects as client_encoding. Now driver-aware: utf8 for
   pgsql, utf8mb4 otherwise. Override via BRAIN_DB_CHARSET env var.

2. Migration 000008 (create_brain_memories) — self-referential FK on
   supersedes_id was declared inside Schema::create{}, causing Postgres
   to evaluate it before the PK index existed ('no unique constraint
   matching given keys'). Split into Schema::create + separate
   Schema::table to guarantee PK is in place when FK is added.

3. Migration 000009 (drop workspace FK) — try/catch inside the Blueprint
   closure couldn't catch deferred SQL failures. Replaced with a
   constraint-exists pre-query against information_schema, supporting
   both pgsql and mariadb/mysql drivers. Fresh installs no longer fail
   trying to drop a constraint that was never created.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-23 12:32:58 +01:00
e58986a3b4 revert fcb9c189e5
revert fix(agentic): harden TODO workspace write

Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-23 12:32:57 +01:00
Codex
cbc262add4 fix(agentic): harden TODO workspace write
Co-Authored-By: Virgil <virgil@lethean.io>
2026-04-23 12:32:57 +01:00
Virgil
25ee288bd2 fix(agentic): align php state and fleet runtime
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-31 08:08:04 +00:00
Virgil
6c69005aff feat(agent): implement fleet and sync RFC surfaces
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-31 07:27:15 +00:00
Snider
be1130f470 agent updates 2026-03-21 11:10:44 +00:00