diff --git a/reference/core/control-center/gaps/gap-reference-catalog.es.md b/reference/core/control-center/gaps/gap-reference-catalog.es.md index 86fd7fa91..84a201a6f 100644 --- a/reference/core/control-center/gaps/gap-reference-catalog.es.md +++ b/reference/core/control-center/gaps/gap-reference-catalog.es.md @@ -382,10 +382,10 @@ Este catálogo explica cada gap: problema, propósito, evidencia, criterios de c - **Criticality:** P2 · **Complexity:** M - **Proposed fix:** Adaptador que define actividad+artefacto esperado, aplica rulesets/skills del tenant, resuelve autorización, invoca Cowork/Claude y captura la evidencia de ejecución para el gate — sobre los puertos de GT-383…394. - **Acceptance criteria:** - - [ ] Una actividad acotada se ejecuta vía el adaptador con permisos/plan/aprobación y captura de evidencia. - - [ ] El ejecutor es reemplazable (cumple el contrato de ejecución del agent-runtime). + - [ ] Una actividad acotada se ejecuta vía el adaptador con permisos/plan/aprobación y captura de evidencia. _(el adaptador es acotado —rechaza tools fuera del catálogo— y el envelope del runtime (approval/policy/trace) lo gobierna; la ejecución viva contra Claude/Cowork requiere el `CoworkClient` real —conector/infra)_ + - [x] El ejecutor es reemplazable (cumple el contrato de ejecución del agent-runtime). _(`CoworkAgentEngineAdapter implements IAgentEnginePort`, drop-in como stub/hermes/swarms)_ - **Dependencies:** GT-387, GT-441. -- **Status:** `PENDING` +- **Status:** `IN-PROGRESS` #### GT-532 diff --git a/reference/core/control-center/gaps/gap-reference-catalog.md b/reference/core/control-center/gaps/gap-reference-catalog.md index cb917fbbf..fdf82b8bf 100644 --- a/reference/core/control-center/gaps/gap-reference-catalog.md +++ b/reference/core/control-center/gaps/gap-reference-catalog.md @@ -382,10 +382,10 @@ This catalog explains each gap: problem, purpose, evidence, closure criteria, an - **Criticality:** P2 · **Complexity:** M - **Proposed fix:** Adapter that defines activity+expected artifact, applies tenant rulesets/skills, resolves authorization, invokes Cowork/Claude and captures execution evidence for the gate — over the GT-383…394 ports. - **Acceptance criteria:** - - [ ] A bounded activity runs via the adapter with permissions/plan/approval and evidence capture. - - [ ] The executor is replaceable (satisfies the agent-runtime execution contract). + - [ ] A bounded activity runs via the adapter with permissions/plan/approval and evidence capture. _(the adapter is bounded —rejects out-of-catalog tools— and the runtime envelope (approval/policy/trace) governs it; live execution against Claude/Cowork needs the real `CoworkClient` —connector/infra)_ + - [x] The executor is replaceable (satisfies the agent-runtime execution contract). _(`CoworkAgentEngineAdapter implements IAgentEnginePort`, drop-in like stub/hermes/swarms)_ - **Dependencies:** GT-387, GT-441. -- **Status:** `PENDING` +- **Status:** `IN-PROGRESS` #### GT-532 diff --git a/reference/core/control-center/gaps/gap-tracking.es.md b/reference/core/control-center/gaps/gap-tracking.es.md index ac62ece65..049c9bd02 100644 --- a/reference/core/control-center/gaps/gap-tracking.es.md +++ b/reference/core/control-center/gaps/gap-tracking.es.md @@ -35,7 +35,7 @@ Este tablero es la única fuente de verdad para deuda técnica, gaps, oportunida | [`GT-528`](./gap-reference-catalog.es.md#gt-528) | **[Wedge · eje 2] Ingesta de DSL Structurizr / C4 → ADR ejecutable.** Convertir modelos Structurizr/C4 (intención de arquitectura, hoy prosa/diagrama) en reglas `enforce:` verificables contra el código real (§13.2). Fix: parser del DSL + mapeo a `NormalizedRule.enforce`; complementa GT-516. **EN-PROGRESO (`c4-compiler.ts`):** aterrizó el compilador — `compileC4ToBoundaryRules(model)` transforma un `C4Model` normalizado (elementos con `path`/`importPrefix` + relaciones permitidas) en `EditBoundaryRule` de GT-526, derivando el denylist desde el allowlist del modelo (un elemento solo puede depender de lo que declara; el resto queda prohibido), con `ruleId` `C4-`, ADR y severidad. **El diagrama C4 se vuelve ejecutable** y se enchufa al gate edit-time (GT-526) y al PR/CI. Verificado end-to-end: un edit de `src/domain` que importa `src/infrastructure` → bloqueado; core-domain 933/933 (+5), tsc limpio. **Pendiente (ingesta):** parsear el `.dsl` crudo de Structurizr (o su export JSON) al `C4Model` normalizado. | `Evolith Core` | Cross | P2 | M | `EN-PROGRESO` | | [`GT-529`](./gap-reference-catalog.es.md#gt-529) | **[Surround · eje 1] Contrato ACL + referencia de integración Jira Enterprise.** Mapear ideas/epics/stories/aprobaciones/releases de Jira a artefactos Evolith preservando origen/identidad/timestamps/linaje, con salvaguardas de transición (completar un workflow de Jira no autoriza una transición de fase). §8.3 / §12. Fix: ACL de sistemas de trabajo externos + guía de integración. **EN-PROGRESO (`domain/external-work-acl.ts`):** aterrizó el ACL puro — `CanonicalWorkItem` con `WorkItemProvenance` (source/externalId/externalKey/url/created/updated), `parseJiraIssue`/`parseJiraIssues` (mapea issues de Jira preservando procedencia; rechaza sin `id` en vez de fabricar identidad), `mapJiraIssueType` (Epic/Story/Task/Version→kind canónico). **Salvaguarda de transición (§9-6):** `authorizesPhaseTransition: false` por contrato + `externalWorkAuthorizesTransition`⇒`false` (completar un workflow de Jira NO autoriza un phase gate). Verificado: core-domain 939/939 (+6), tsc limpio. **Pendiente (conector/infra + doc):** fetch read-only de la Jira REST API + la guía de integración documentada. | `Evolith Core` | Cross | P1 | L | `EN-PROGRESO` | | [`GT-530`](./gap-reference-catalog.es.md#gt-530) | **[Surround · eje 1] Adaptador Langfuse → evidencia canónica.** Mapear traces/evaluaciones/costo/latencia/versión-de-prompt/tool-calls de Langfuse al modelo de evidencia de Evolith, para no reconstruir una plataforma de telemetría LLM. §8.1 / §12. Fix: `LangfuseEvidenceAdapter` vía puerto de observabilidad. **EN-PROGRESO (`domain/observability-evidence.ts`):** aterrizó el mapper puro + forma portable — `ObservabilityEvidence` (traceId/model/promptVersion/costUsd/latencyMs/totalTokens/toolCalls/evaluations/url, provider-neutral §9-5), `mapLangfuseTrace` (agrega costo/tokens/latencia de las observaciones, toma model/prompt de la 1ª GENERATION, colecta tool-calls distintos, mapea scores→evaluations; trace sin id⇒null) y el puerto `IObservabilityEvidenceSource`. Verificado: core-domain 945/945 (+6), tsc limpio. **Pendiente (conector/infra):** el fetch read-only de la Langfuse API detrás del puerto. | `Evolith Core` | Cross | P2 | L | `EN-PROGRESO` | -| [`GT-531`](./gap-reference-catalog.es.md#gt-531) | **[Surround · eje 1] Adaptador Cowork/Claude como ejecutor gobernado acotado.** Ejecutor de actividades con permisos/planes/aprobaciones/captura de evidencia, tratando a Claude como uno de varios ejecutores reemplazables (§8.2, §9). Extiende el épico agent-runtime GT-383…394 (HITL GT-441 / adapters GT-438). | `agent-runtime` | Cross | P2 | M | `PENDIENTE` | +| [`GT-531`](./gap-reference-catalog.es.md#gt-531) | **[Surround · eje 1] Adaptador Cowork/Claude como ejecutor gobernado acotado.** Ejecutor de actividades con permisos/planes/aprobaciones/captura de evidencia, tratando a Claude como uno de varios ejecutores reemplazables (§8.2, §9). Extiende el épico agent-runtime GT-383…394 (HITL GT-441 / adapters GT-438). **EN-PROGRESO (`cowork-agent.adapter.ts`):** aterrizó el `CoworkAgentEngineAdapter` — implementa el mismo `IAgentEnginePort` que stub/hermes/swarms (Claude Cowork como ejecutor **reemplazable**), y es **acotado**: nunca propone una herramienta fuera del catálogo de skills gobernado (una propuesta de Cowork/LLM a una capacidad inexistente se rechaza en vez de inventarse). El envelope del runtime (approval GT-441 / policy / trace) ya lo gobierna; la llamada viva a Claude va detrás de `CoworkClient` inyectable (sin cliente = determinista, como el stub). Verificado: agent-runtime 92/92, tsc limpio, surface-freeze GT-388 actualizado. **Pendiente (conector/infra):** el `CoworkClient` real contra la Claude/Cowork API. | `agent-runtime` | Cross | P2 | M | `EN-PROGRESO` | | [`GT-532`](./gap-reference-catalog.es.md#gt-532) | **[Surround · eje 1] Vistas ejecutivas de portafolio + adaptadores marketplace + paquetes de gobernanza por tenant.** Mejora de adopción empresarial y escala de ecosistema (§12 P2); mayormente Tracker (plano de captura de valor enterprise). | `Tracker` | Cross | P3 | XL | `PENDIENTE` | | [`GT-486`](./gap-reference-catalog.es.md#gt-486) | **el CLI no emitió un envelope ADR-0073 parseable para sdlc-status.** La salida no pudo parsearse en un envelope { success, data\|error, meta }. (Auto-detectado por el agente de pruebas exploratorias en la operación `sdlc-status`.) | `Evolith CLI` | Cross | P2 | S | `COMPLETADO` | | [`GT-487`](./gap-reference-catalog.es.md#gt-487) | **el CLI no emitió un envelope ADR-0073 parseable para sdlc-handoff.** La salida no pudo parsearse en un envelope { success, data\|error, meta }. (Auto-detectado por el agente de pruebas exploratorias en la operación `sdlc-handoff`.) | `Evolith CLI` | Cross | P2 | S | `COMPLETADO` | @@ -547,7 +547,7 @@ Este tablero es la única fuente de verdad para deuda técnica, gaps, oportunida | [`GT-246`](./gap-reference-catalog.es.md#gt-246) | Implementar experimentos Chaos Mesh/Litmus | `QA` | Cross | P3 | L | `COMPLETADO` | -**Progreso:** 496 / 532 completados · 19 en progreso · 15 pendientes · 2 diferido +**Progreso:** 496 / 532 completados · 20 en progreso · 14 pendientes · 2 diferido **Oleada 2026-06-23 (auditoría profunda de Winston III):** Añadidos 14 gaps nuevos `GT-212`…`GT-225` del Winston Audit Playbook que cubren: higiene de estado ADR (GT-212), metadata + presupuestos operativos + corpus de guías por topología (GT-213, GT-217, GT-219), observabilidad + OpenAPI en controladores REST (GT-214, GT-215), paridad de input-schemas OPA + densidad de tests por topología (GT-216, GT-222), plantillas de rollback + on-call de Fase 05 (GT-218), cobertura de ramas CLI + paridad de envelope --format + limpieza de skip-list (GT-220, GT-224, GT-225), audit logging HTTP de MCP (GT-221), y tests e2e de paridad cross-surface (GT-223). diff --git a/reference/core/control-center/gaps/gap-tracking.md b/reference/core/control-center/gaps/gap-tracking.md index 40a779721..1c1f64337 100644 --- a/reference/core/control-center/gaps/gap-tracking.md +++ b/reference/core/control-center/gaps/gap-tracking.md @@ -35,7 +35,7 @@ This board is the single source of truth for technical debt, gaps, opportunities | [`GT-528`](./gap-reference-catalog.md#gt-528) | **[Wedge · axis 2] Structurizr / C4 DSL ingestion → executable ADR.** Turn Structurizr/C4 models (architecture intent, today prose/diagram) into `enforce:` rules verifiable against real code (§13.2). Fix: DSL parser + mapping to `NormalizedRule.enforce`; complements GT-516. **IN-PROGRESS (`c4-compiler.ts`):** landed the compiler — `compileC4ToBoundaryRules(model)` turns a normalized `C4Model` (elements with `path`/`importPrefix` + allowed relationships) into GT-526 `EditBoundaryRule`s, deriving the denylist from the model's allowlist (an element may only depend on what it declares; everything else is forbidden), with `ruleId` `C4-`, ADR and severity. **The C4 diagram becomes executable** and feeds the edit-time gate (GT-526) and PR/CI. Verified end-to-end: a `src/domain` edit importing `src/infrastructure` → blocked; core-domain 933/933 (+5), tsc clean. **Remaining (ingestion):** parse the raw Structurizr `.dsl` (or its JSON export) into the normalized `C4Model`. | `Evolith Core` | Cross | P2 | M | `IN-PROGRESS` | | [`GT-529`](./gap-reference-catalog.md#gt-529) | **[Surround · axis 1] ACL contract + Jira Enterprise integration reference.** Map Jira ideas/epics/stories/approvals/releases to Evolith artifacts preserving origin/identity/timestamps/lineage, with transition safeguards (completing a Jira workflow does not authorize a phase transition). §8.3 / §12. Fix: external work-system ACL + integration guide. **IN-PROGRESS (`domain/external-work-acl.ts`):** landed the pure ACL — `CanonicalWorkItem` with `WorkItemProvenance` (source/externalId/externalKey/url/created/updated), `parseJiraIssue`/`parseJiraIssues` (maps Jira issues preserving provenance; rejects a missing `id` rather than fabricating identity), `mapJiraIssueType` (Epic/Story/Task/Version→canonical kind). **Transition safeguard (§9-6):** `authorizesPhaseTransition: false` by contract + `externalWorkAuthorizesTransition`⇒`false` (completing a Jira workflow does NOT authorize a phase gate). Verified: core-domain 939/939 (+6), tsc clean. **Remaining (connector/infra + doc):** the read-only Jira REST API fetch + the documented integration guide. | `Evolith Core` | Cross | P1 | L | `IN-PROGRESS` | | [`GT-530`](./gap-reference-catalog.md#gt-530) | **[Surround · axis 1] Langfuse adapter → canonical evidence.** Map Langfuse traces/evaluations/cost/latency/prompt-version/tool-calls to Evolith's evidence model, to avoid rebuilding an LLM telemetry platform. §8.1 / §12. Fix: `LangfuseEvidenceAdapter` via the observability port. **IN-PROGRESS (`domain/observability-evidence.ts`):** landed the pure mapper + portable shape — `ObservabilityEvidence` (traceId/model/promptVersion/costUsd/latencyMs/totalTokens/toolCalls/evaluations/url, provider-neutral §9-5), `mapLangfuseTrace` (aggregates cost/tokens/latency across observations, takes model/prompt from the first GENERATION, collects distinct tool-calls, maps scores→evaluations; a trace with no id⇒null) and the `IObservabilityEvidenceSource` port. Verified: core-domain 945/945 (+6), tsc clean. **Remaining (connector/infra):** the read-only Langfuse API fetch behind the port. | `Evolith Core` | Cross | P2 | L | `IN-PROGRESS` | -| [`GT-531`](./gap-reference-catalog.md#gt-531) | **[Surround · axis 1] Cowork/Claude adapter as a bounded governed executor.** Activity executor with permissions/plans/approvals/evidence capture, treating Claude as one of several replaceable executors (§8.2, §9). Extends the agent-runtime epic GT-383…394 (HITL GT-441 / adapters GT-438). | `agent-runtime` | Cross | P2 | M | `PENDING` | +| [`GT-531`](./gap-reference-catalog.md#gt-531) | **[Surround · axis 1] Cowork/Claude adapter as a bounded governed executor.** Activity executor with permissions/plans/approvals/evidence capture, treating Claude as one of several replaceable executors (§8.2, §9). Extends the agent-runtime epic GT-383…394 (HITL GT-441 / adapters GT-438). **IN-PROGRESS (`cowork-agent.adapter.ts`):** landed `CoworkAgentEngineAdapter` — implements the same `IAgentEnginePort` as stub/hermes/swarms (Claude Cowork as a **replaceable** executor), and is **bounded**: it never proposes a tool outside the governed skill catalog (a Cowork/LLM proposal for a non-existent capability is rejected, not invented). The runtime envelope (approval GT-441 / policy / trace) already governs it; the live Claude call sits behind an injectable `CoworkClient` (no client = deterministic, like the stub). Verified: agent-runtime 92/92, tsc clean, GT-388 surface-freeze updated. **Remaining (connector/infra):** the real `CoworkClient` against the Claude/Cowork API. | `agent-runtime` | Cross | P2 | M | `IN-PROGRESS` | | [`GT-532`](./gap-reference-catalog.md#gt-532) | **[Surround · axis 1] Executive portfolio views + marketplace adapters + per-tenant governance packages.** Enterprise-adoption and ecosystem-scale improvement (§12 P2); mostly Tracker (enterprise value-capture plane). | `Tracker` | Cross | P3 | XL | `PENDING` | | [`GT-486`](./gap-reference-catalog.md#gt-486) | **cli did not emit a parseable ADR-0073 envelope for sdlc-status.** Output could not be parsed into an { success, data\|error, meta } envelope. (Auto-detected by the exploratory test agent on operation `sdlc-status`.) | `Evolith CLI` | Cross | P2 | S | `DONE` | | [`GT-487`](./gap-reference-catalog.md#gt-487) | **cli did not emit a parseable ADR-0073 envelope for sdlc-handoff.** Output could not be parsed into an { success, data\|error, meta } envelope. (Auto-detected by the exploratory test agent on operation `sdlc-handoff`.) | `Evolith CLI` | Cross | P2 | S | `DONE` | @@ -547,7 +547,7 @@ This board is the single source of truth for technical debt, gaps, opportunities | [`GT-246`](./gap-reference-catalog.md#gt-246) | Implement Chaos Mesh/Litmus experiments | `QA` | Cross | P3 | L | `DONE` | -**Progress:** 496 / 532 done · 19 in progress · 15 pending · 2 deferred +**Progress:** 496 / 532 done · 20 in progress · 14 pending · 2 deferred **Wave 2026-06-23 (Winston deep audit III):** Added 14 new gaps `GT-212`…`GT-225` from the Winston Audit Playbook covering: ADR status hygiene (GT-212), topology manifest metadata + operational budgets + guidance corpus (GT-213, GT-217, GT-219), REST controller observability + OpenAPI (GT-214, GT-215), OPA input-schema parity + per-topology test density (GT-216, GT-222), SDLC Phase 05 rollback + on-call templates (GT-218), CLI branch coverage + envelope format coverage + skip-list cleanup (GT-220, GT-224, GT-225), MCP HTTP audit logging (GT-221), and cross-surface parity e2e tests (GT-223). diff --git a/src/packages/agent-runtime/src/__tests__/cowork-agent.adapter.spec.ts b/src/packages/agent-runtime/src/__tests__/cowork-agent.adapter.spec.ts new file mode 100644 index 000000000..538ba878f --- /dev/null +++ b/src/packages/agent-runtime/src/__tests__/cowork-agent.adapter.spec.ts @@ -0,0 +1,46 @@ +import { CoworkAgentEngineAdapter, type CoworkClient } from '../adapters/engine/cowork-agent.adapter'; +import type { AgentRuntimeRequest } from '../../domain/contracts/agent-runtime-request'; +import type { SkillDescriptor } from '../../domain/contracts/capability'; + +describe('CoworkAgentEngineAdapter (GT-531 — bounded, replaceable governed executor)', () => { + const skills: SkillDescriptor[] = [ + { id: 'foo', description: 'Does foo', intents: ['foo'], type: 'effect', handler: jest.fn() } as unknown as SkillDescriptor, + { id: 'bar', description: 'Does bar', intents: ['bar'], type: 'effect', handler: jest.fn() } as unknown as SkillDescriptor, + ]; + + const request: AgentRuntimeRequest = { + intent: 'do the thing', + context: { tenantId: 'tenant-1', productId: 'prod-1', initiativeId: 'init-1', phase: 'build', gate: 'f2' }, + }; + + it('proposes a tool the Cowork client selected WHEN it is in the governed catalog', async () => { + const client: CoworkClient = { + propose: jest.fn().mockResolvedValue({ tool: 'foo', arguments: { a: 1 }, rationale: 'Cowork picked foo.' }), + }; + const plan = await new CoworkAgentEngineAdapter({ client }).plan(request, skills); + expect(plan).toEqual({ engine: 'cowork', proposedTool: 'foo', proposedArguments: { a: 1 }, rationale: 'Cowork picked foo.' }); + }); + + it('REJECTS a tool outside the catalog — bounded executor never invents a capability', async () => { + const client: CoworkClient = { + propose: jest.fn().mockResolvedValue({ tool: 'delete-everything', rationale: 'trust me' }), + }; + const plan = await new CoworkAgentEngineAdapter({ client }).plan(request, skills); + expect(plan.proposedTool).toBeUndefined(); + expect(plan.engine).toBe('cowork'); + expect(plan.rationale).toMatch(/not in the governed skill catalog — rejected/); + expect(plan.recommendations).toEqual(["Try 'foo': Does foo", "Try 'bar': Does bar"]); + }); + + it('is deterministic with NO client wired (no external call), like the stub', async () => { + const plan = await new CoworkAgentEngineAdapter().plan(request, skills); + expect(plan.proposedTool).toBeUndefined(); + expect(plan.engine).toBe('cowork'); + expect(plan.recommendations).toHaveLength(2); + }); + + it('treats Cowork as replaceable — same IAgentEnginePort as stub/hermes/swarms', () => { + const adapter = new CoworkAgentEngineAdapter(); + expect(typeof adapter.plan).toBe('function'); + }); +}); diff --git a/src/packages/agent-runtime/src/__tests__/public-surface.spec.ts b/src/packages/agent-runtime/src/__tests__/public-surface.spec.ts index a77c3848d..7746939da 100644 --- a/src/packages/agent-runtime/src/__tests__/public-surface.spec.ts +++ b/src/packages/agent-runtime/src/__tests__/public-surface.spec.ts @@ -22,6 +22,8 @@ const ADAPTERS_SURFACE = [ 'AutoApprovalAdapter', 'ChatApprovalAdapter', 'CliCommunicationGatewayAdapter', + 'COWORK_ENGINE', + 'CoworkAgentEngineAdapter', 'CompositeTrackerTraceAdapter', 'DEFAULT_SKILLS', 'DenyByDefaultApprovalAdapter', diff --git a/src/packages/agent-runtime/src/adapters/engine/cowork-agent.adapter.ts b/src/packages/agent-runtime/src/adapters/engine/cowork-agent.adapter.ts new file mode 100644 index 000000000..126f5f082 --- /dev/null +++ b/src/packages/agent-runtime/src/adapters/engine/cowork-agent.adapter.ts @@ -0,0 +1,64 @@ +/** + * CoworkAgentEngineAdapter (GT-531 · axis 1 — positioning §8.2 / §9-4). + * + * Treats Claude Cowork as ONE OF SEVERAL REPLACEABLE governed executors behind + * {@link IAgentEnginePort} — the same port stub/hermes/swarms implement, so it drops in with no + * change to the runtime. It is BOUNDED: it only ever proposes a tool that EXISTS in the available + * skill catalog, so a Cowork/LLM proposal for a capability outside the catalog is rejected rather + * than invented. The runtime's existing envelope — approval (GT-441), policy validation, trace — + * governs whatever it proposes; this adapter adds the executor-level bound. + * + * The live Claude/Cowork call is injected as a {@link CoworkClient} (follow-on infra); with no + * client wired the adapter is deterministic (no external call), like the stub engine. + */ + +import type { AgentRuntimeRequest } from '../../domain/contracts/agent-runtime-request'; +import type { SkillDescriptor } from '../../domain/contracts/capability'; +import type { AgentEnginePlan, IAgentEnginePort } from '../../domain/ports/agent-engine.port'; + +export const COWORK_ENGINE = 'cowork'; + +/** A raw proposal from Cowork before governance is applied. */ +export interface CoworkProposal { + readonly tool?: string; + readonly arguments?: Readonly>; + readonly rationale?: string; +} + +/** The live Cowork/Claude call, injected. Follow-on infra; the adapter works without it. */ +export interface CoworkClient { + propose(request: AgentRuntimeRequest, availableSkills: readonly SkillDescriptor[]): Promise; +} + +export interface CoworkAdapterOptions { + readonly client?: CoworkClient; +} + +export class CoworkAgentEngineAdapter implements IAgentEnginePort { + constructor(private readonly options: CoworkAdapterOptions = {}) {} + + async plan(request: AgentRuntimeRequest, availableSkills: readonly SkillDescriptor[]): Promise { + const proposal = this.options.client + ? await this.options.client.propose(request, availableSkills) + : undefined; + + const inCatalog = !!proposal?.tool && availableSkills.some((s) => s.id === proposal.tool); + if (!inCatalog) { + // Bounded executor: never surface a tool outside the governed catalog. + return { + engine: COWORK_ENGINE, + rationale: proposal?.tool + ? `Cowork proposed '${proposal.tool}', which is not in the governed skill catalog — rejected (bounded executor).` + : `Cowork proposed no in-catalog tool for intent '${request.intent}'.`, + recommendations: availableSkills.slice(0, 3).map((s) => `Try '${s.id}': ${s.description}`), + }; + } + + return { + engine: COWORK_ENGINE, + proposedTool: proposal!.tool, + proposedArguments: proposal!.arguments, + rationale: proposal!.rationale ?? `Cowork selected '${proposal!.tool}' from the governed catalog.`, + }; + } +} diff --git a/src/packages/agent-runtime/src/adapters/index.ts b/src/packages/agent-runtime/src/adapters/index.ts index 4da9ab278..455526e02 100644 --- a/src/packages/agent-runtime/src/adapters/index.ts +++ b/src/packages/agent-runtime/src/adapters/index.ts @@ -76,6 +76,8 @@ export { HermesAgentAdapter } from './engine/hermes-agent.adapter'; export type { HermesClient, HermesAdapterOptions } from './engine/hermes-agent.adapter'; export { SwarmsAgentAdapter } from './engine/swarms-agent.adapter'; export type { SwarmsClient, SwarmsAdapterOptions } from './engine/swarms-agent.adapter'; +export { CoworkAgentEngineAdapter, COWORK_ENGINE } from './engine/cowork-agent.adapter'; +export type { CoworkClient, CoworkProposal, CoworkAdapterOptions } from './engine/cowork-agent.adapter'; export { RoutingAgentAdapter } from './engine/routing-agent.adapter'; export type { EngineRouterConfig } from './engine/routing-agent.adapter'; export { PolicyBasedEngineRouter } from './engine/policy-based-engine-router';