@intent-driven/runtime-local
v0.14.0
Published
Standalone Fold-runtime для local quickstart: stateful Φ + agent/exec + approvals + state — то, что делает host idf/server, но как npm-пакет
Downloads
2,033
Maintainers
Readme
@intent-driven/runtime-local
Standalone Fold-runtime для локального quickstart'а. Принимает ontology.js (сгенерированный idf full-bootstrap), поднимает HTTP-сервер с эндпоинтами, которые ожидает @intent-driven/mcp-server для подключения к Claude Desktop / Cursor / Zed.
Статус: v0.6 — transition history-tracking (full pair validation для kind:transition invariants). Поддерживает все эндпоинты v0.5 +
opts.historyавтоматически builds в engine submit.
Зачем
До этого пакета чтобы поднять Fold-runtime локально нужно было git clone idf + npm install + npm run server в host-репе. Это блокер коробочности: пользователь не должен знать про host. После этого пакета:
idf serve --ontology ./ontology.js # планируется в @intent-driven/cli
# или программно:
import { createRuntime } from '@intent-driven/runtime-local';
const runtime = createRuntime({
ontology: require('./ontology.js'),
seed: require('./seed.json'), // опц. — массив эффектов
});
await runtime.start();Установка
npm install @intent-driven/runtime-localPeer-зависимость: @intent-driven/core@>=0.49.0 (через @intent-driven/engine).
API
createRuntime(opts)
Создаёт runtime-инстанс. Не стартует сервер — для этого вызови .start().
| Опция | Тип | Default | Описание |
|---|---|---|---|
| ontology | object | required | IDF ontology — { entities, intents, roles, projections, ... }. |
| seed | array | [] | Pre-confirmed эффекты для начального состояния Φ. Каждый — {id, intent_id, alpha, target, context, value?, status: 'confirmed', created_at}. Primitive value (строки/числа) нормализуются в JSON-encoded автоматически. |
| port | number | 3001 | Порт. 0 = random (для тестов). |
| host | string | '127.0.0.1' | Bind-адрес. |
Возвращает { app, ontology, domain, engine, persistence, start(), stop() }. engine — instance @intent-driven/engine, для прямого использования (e.g., тесты).
runtime.start() → Promise<{url, port, host}>
Поднимает Express-сервер. Загружает seed в persistence перед listen. Возвращает actual URL/port (полезно при port: 0).
runtime.stop() → Promise<void>
Закрывает сервер.
Эндпоинты
| Метод | Путь | Назначение |
|---|---|---|
| GET | /api/health | Liveness check для idf doctor и MCP-server. Возвращает {status, domain, runtime, version}. |
| GET | /api/typemap | Сводка ontology: entities/intents/roles names. |
| GET | /api/agent/:domain/schema | Full ontology snapshot для MCP discovery. 503 если domain не совпадает. |
| GET | /api/state/current | Folded world snapshot — {domain, world: {products: [...], orders: [...]}}. |
| GET | /api/agent/:domain/world | Тот же world, что и /api/state/current. Этот endpoint вызывает @intent-driven/mcp-server для resource-чтения. 503 при mismatch domain. |
| POST | /api/agent/:domain/exec/:intentId | Ingest intent через engine.submit. Generic builder для add/replace/remove. Возвращает 200 {status:'confirmed', effect} для intent'ов без lifecycle, 202 {status:'pending_approval', approvalRequestId, ...} для intent'ов с lifecycle.requiresApproval, или 409 при invariant violation. 400 для read-intents, 404 для unknown intent, 503 для wrong domain. |
| GET | /api/approvals/pending?domain=NAME&as=ROLE | Pending ApprovalRequest'ы видимые caller'у (фильтр по fromRole). Lazy-expiry: requests с now > expiresAt автоматически переводятся в expired до возврата. |
| POST | /api/approvals/:id/approve (body {reason?}) | Approver одобряет; effectsPlanned ingest'ятся через engine.submit. AR получает status='approved' + approvedBy + approvedAt. 403 если caller'а роль не в fromRole. 409 если уже terminal status / expired. |
| POST | /api/approvals/:id/reject (body {reason?}) | Аналогично approve, но без ingest'а. status='rejected'. |
POST /api/agent/:domain/exec/:intentId
Тело запроса: { params: { ... } }.
buildEffect() строит effect по generic-семантике (идентично host'овскому genericBuildEffects):
alpha=add→context = {...params, id: params.id || uuid},value = nullalpha=replacetarget=Entity.field→context = {id: params.id},value = JSON.stringify(params[field])alpha=replacetarget=Entity→context = {...params},value = nullalpha=remove→context = {id: params.id || params['<entity>Id']},value = nullalpha=read→ 400 (читай через GET/api/state/current)
Лежит на engine.submit, поэтому invariants всех 6 kinds автоматически проверяются (role-capability / referential / transition / cardinality / aggregate / expression).
Approval lifecycle: intents с
lifecycle.requiresApproval = { from: ['admin'], timeoutMs: 60_000 }автоматически работают через ApprovalRequest.lifecycleAugmenterдобавляетApprovalRequestentity и augment'ит approver/proposer visibleFields на старте. POST exec возвращает 202 +approvalRequestId; реальный ingest происходит в/approvals/:id/approve. RBAC:?as=ROLEquery (без auth в v0.5; JWT — будущая итерация).
Caller role
В v0.5 caller's role резолвится через ?as=ROLE query parameter. Без этого — 'agent' по умолчанию. JWT/Bearer-token auth — в будущих релизах.
# Approver одобряет от имени admin'а
curl -X POST http://localhost:3001/api/approvals/ar_abc.../approve?as=admin \
-d '{"reason":"validated by IT"}'Roadmap (следующие PR)
- v0.6:
GET /api/state/at?t=ISO+/api/state/diff?from=&to=— time-travel - v0.7: SSE-стрим
/api/approvals/streamдляidf approvals --watch - v0.8: timer-driven approval expiry (вместо lazy-expiry в /pending)
- v0.9: JWT auth + per-request viewer.scope
Лицензия
MIT. © Ignat Dubovsky.
