diff --git a/projects/agents/01-overview.md b/projects/agents/01-overview.md new file mode 100644 index 000000000..9447f179e --- /dev/null +++ b/projects/agents/01-overview.md @@ -0,0 +1,177 @@ + + +# Agentic Goals: Overview + +Status: Draft + +## Vision + +Give a user one place to state a high-level goal, align on what success means, and authorize a bounded organization of agents and workflows to pursue it. + +The experience begins with: + +```text +/goal +``` + +A lead agent collaborates with the user to turn that objective into a goal contract and a versioned execution plan. After approval, the lead coordinates specialized agents, deterministic tools, and OSMO workflows while preserving a clear path for inspection, steering, approval, cancellation, and evidence-based completion. + +## Product thesis + +OSMO is the execution substrate, not the agentic state machine. + +OSMO is well suited to static, containerized DAG execution across heterogeneous Kubernetes clusters. It already provides task dependencies, resource scheduling, datasets and artifacts, credentials, retries, logs, rendered-spec dry-run, and validation. It does not currently provide dynamic graph expansion, native child workflows, durable conversations, approval gates, or hierarchical agent semantics. + +The agentic layer therefore lives in a new control plane above OSMO: + +```mermaid +flowchart LR + User[User] <--> Lead["Lead session"] + Lead <--> Coordinator["Agent control plane"] + Coordinator <--> GoalGraph["Versioned goal graph"] + Coordinator <--> Policy["Policy and approvals"] + Coordinator -->|"submit static capsule"| OSMO["OSMO API"] + OSMO --> Workflows["Static OSMO workflows"] + Workflows -->|"status and artifacts"| Coordinator + Workers["Bounded agent runs"] -->|"propose results or children"| Coordinator + Coordinator --> Workers +``` + +OSMO validates a complete workflow before submission and materializes its groups and tasks as a static DAG. See the current [workflow submission API](../../external/src/service/core/workflow/workflow_service.py), [workflow schema](../../external/src/utils/job/workflow.py), and [submit job](../../external/src/utils/job/jobs.py). + +## Three distinct graphs + +The design must keep three related structures separate: + +1. **Goal and delegation graph** + - Describes ownership: which agent or deterministic process is responsible for each sub-goal. + - May grow as bounded agents propose additional work. + +2. **Execution graph** + - Describes dependencies, joins, approvals, evaluations, retries, and plan revisions. + - Is dynamic only through durable, versioned, auditable changes. + +3. **OSMO workflow DAG** + - Describes a static execution capsule submitted to OSMO. + - Is immutable after submission; a materially changed plan produces a new workflow or attempt. + +Agent loops and replanning mean the complete system is a durable state machine over graph revisions, not one recursively mutable DAG. + +## Core concepts + +- **Goal**: The user-visible objective and durable root of all work. +- **Goal contract**: Objective, non-goals, acceptance criteria, constraints, deadline, budget, autonomy policy, and permitted capabilities. +- **Plan revision**: An immutable version of the proposed execution graph. +- **Workstream**: A user-comprehensible sub-goal owned by one agent or deterministic process. +- **Node run**: One execution of a workstream contract. +- **Attempt**: One retry or revised strategy for a node run. +- **Agent run**: A bounded model-driven loop with typed inputs, outputs, tools, budget, stop conditions, and evaluator. +- **Workflow capsule**: A static OSMO workflow used for coarse, isolated, resource-intensive, or data-bearing execution. +- **Approval**: A human decision that grants or denies a specific authority envelope. +- **Artifact**: A typed, addressable output used as evidence or as input to later work. +- **Evidence**: Information that supports an acceptance criterion or a material decision. +- **Event**: An append-only record of state changes, decisions, actions, and external bindings. + +## Execution node classes + +The initial system supports three explicit node classes: + +1. **Deterministic job** + - Runs a script, tool, API call, or OSMO task from typed inputs. + - Has predictable control flow even when the external system may fail. + +2. **Bounded agent run** + - Uses a model to reason, select tools, and produce a typed result. + - Is constrained by a tool policy, budget, deadline, maximum steps, and evaluator. + +3. **Constrained agent-tool loop** + - Uses deterministic tools inside a nondeterministic reasoning harness. + - Treats the harness as controlled and auditable without claiming model behavior is deterministic. + +There is no unbounded “pure agent” node. Every node has an enforceable contract and termination policy. + +## Design principles + +- `/goal` creates a draft; it never starts execution by itself. +- Human approval grants bounded authority, not blanket autonomy. +- Plan changes are revisions, not invisible mutations. +- Delegation depth, fan-out, concurrency, spend, compute, tokens, and wall time are bounded. +- Lightweight planning and model calls stay in the agent control plane; OSMO runs coarse execution capsules. +- State lives outside chat and can survive process, model, and UI restarts. +- Agents exchange typed artifacts and messages rather than relying on copied transcripts. +- Completion is based on acceptance criteria and evidence, not agent self-declaration. +- Every external side effect is attributable, policy-checked, and idempotent or compensatable. +- The lead summarizes and governs; it does not ingest every raw child transcript into one context window. + +## End-to-end experience + +```mermaid +flowchart LR + Prompt["/goal prompt"] --> Frame["Frame goal contract"] + Frame --> Plan["Create plan revision"] + Plan --> Preview["Preview and validate"] + Preview --> Approval["Approve authority envelope"] + Approval --> Execute["Execute and coordinate"] + Execute --> Evaluate["Evaluate evidence"] + Evaluate --> Complete["Complete or revise"] + Execute -->|"material change"| Plan + Execute -->|"human decision"| Approval +``` + +The detailed lifecycle is defined in [02-lifecycle.md](02-lifecycle.md). The user experience is defined in [03-ui.md](03-ui.md) and [05-human-interfaces.md](05-human-interfaces.md). + +## Scope + +The first validation should support: + +- One technical user. +- A chat-first `/goal` entry point and a visual run console. +- One lead agent and one bounded level of delegated workers. +- Deterministic jobs, bounded agent runs, and coarse OSMO workflow capsules. +- Versioned plans and explicit approval envelopes. +- One controlled replan path. +- Durable status, evidence, cost, and lineage. +- Goal-wide pause and best-effort cancellation semantics. +- Independent evaluation before completion. + +## Non-goals for the first validation + +- Unlimited recursive delegation. +- Treating every LLM turn or tool call as an OSMO workflow. +- Mutating an in-flight OSMO workflow DAG. +- Exactly-once execution across arbitrary external tools. +- Reproducing nondeterministic model outputs during replay. +- Replacing OSMO workflow, resource, log, event, or shell views. +- Autonomous privilege escalation or unrestricted credential propagation. +- A general-purpose organizational simulation based on the CEO metaphor. + +## First success criteria + +The concept is viable when a representative goal can demonstrate: + +- Recovery after coordinator restart without duplicate OSMO submissions or duplicate side effects. +- End-to-end lineage from the goal prompt through plans, agents, tools, OSMO workflow IDs, artifacts, approvals, and evaluation. +- Enforced delegation, resource, time, and spend limits. +- Human inspection and steering of a nested worker without losing the lead context. +- A failed or timed-out child cannot strand the parent indefinitely. +- Goal-wide stop behavior eventually reconciles all descendants. +- Every completion claim maps to explicit acceptance criteria and evidence. +- The user can always answer: what is happening, why, what changed, what needs attention, what supports completion, and what can be safely stopped. + +## Document map + +- [02-lifecycle.md](02-lifecycle.md): Goal, plan, node, attempt, approval, and termination state machines. +- [03-ui.md](03-ui.md): Chat-first experience and visual run console. +- [04-lead-agent.md](04-lead-agent.md): Lead responsibilities, decision boundaries, and context management. +- [05-human-interfaces.md](05-human-interfaces.md): Approvals, attention routing, steering, notifications, and manual intervention. +- [06-workflow-construction.md](06-workflow-construction.md): Compiling execution nodes into static OSMO workflows. +- [07-agent-construction.md](07-agent-construction.md): Agent manifests, harnesses, capabilities, budgets, and evaluators. +- [08-agent-agent-communication.md](08-agent-agent-communication.md): Typed messages, artifacts, delegation, joins, and event semantics. diff --git a/projects/agents/02-lifecycle.md b/projects/agents/02-lifecycle.md new file mode 100644 index 000000000..ddd5dfe02 --- /dev/null +++ b/projects/agents/02-lifecycle.md @@ -0,0 +1,259 @@ + + +# Agentic Goals: Lifecycle + +Status: Draft + +## Purpose + +Define durable, comprehensible lifecycle semantics for goals that may contain plan revisions, bounded agent loops, deterministic work, human decisions, and multiple OSMO workflow attempts. + +The lifecycle must remain correct when: + +- The coordinator, model runtime, UI, or network restarts. +- A child agent proposes more work. +- A user changes direction during execution. +- An OSMO submission is duplicated, delayed, canceled, or restarted. +- A tool succeeds but its response is lost. +- A parent fails while children remain active. +- Evaluation rejects an apparently successful result. + +## Lifecycle model + +The source of truth is an append-only event history plus transactional projections. Chat messages, model context, and OSMO status are inputs to reconciliation; none is the sole system of record. + +Every transition records: + +- Entity ID and prior state. +- New state and reason. +- Actor: user, lead, worker, policy engine, evaluator, reconciler, tool, or OSMO. +- Plan revision and authority envelope in force. +- Correlation and causation IDs. +- Relevant attempt, artifact, approval, and OSMO workflow IDs. +- Timestamp and idempotency key. + +## Goal lifecycle + +```mermaid +stateDiagram-v2 + [*] --> Draft + Draft --> AwaitingApproval: plan ready + AwaitingApproval --> Draft: revise or reject + AwaitingApproval --> Running: approve and start + Running --> WaitingOnUser: human decision required + WaitingOnUser --> Running: decision received + Running --> Evaluating: execution converged + Evaluating --> Completed: criteria satisfied + Evaluating --> Running: remediation approved + Evaluating --> Blocked: no valid next action + Running --> Blocked: dependency or policy prevents progress + Blocked --> Running: blocker resolved + Draft --> Stopped: abandon + AwaitingApproval --> Stopped: abandon + Running --> Stopping: stop requested + WaitingOnUser --> Stopping: stop requested + Blocked --> Stopping: stop requested + Stopping --> Stopped: descendants reconciled + Running --> Failed: terminal invariant violated + Stopping --> Failed: reconciliation cannot complete +``` + +### Goal states + +- **Draft**: The goal contract and plan may change freely. No execution side effects are permitted. +- **Awaiting approval**: A specific plan revision and authority envelope are ready for a human decision. +- **Running**: The coordinator may dispatch work within the approved envelope. +- **Waiting on user**: Progress is intentionally suspended on a required human decision. Work independent of that decision may continue only if the plan explicitly permits it. +- **Evaluating**: Planned execution has converged and independent acceptance checks are running. +- **Blocked**: No permitted action can currently make progress. The goal may recover when a dependency, policy, credential, resource, or human-provided input changes. +- **Stopping**: No new work is dispatched; the coordinator is reconciling queued and active descendants according to the selected stop mode. +- **Stopped**: The user or policy intentionally ended the goal. Partial artifacts and evidence remain available. +- **Completed**: Acceptance criteria are satisfied with recorded evidence. +- **Failed**: The system cannot preserve a required invariant or has exhausted approved recovery paths. Ordinary child failure does not automatically imply goal failure. + +`Completed`, `Stopped`, and `Failed` are terminal for a goal run. Continuing later creates a new run or an explicit successor linked to the prior run. + +## Plan revision lifecycle + +Plans are immutable after proposal. Editing creates a new revision. + +```mermaid +stateDiagram-v2 + [*] --> DraftPlan + DraftPlan --> Validating: preview requested + Validating --> DraftPlan: validation issue + Validating --> ReadyPlan: checks pass + ReadyPlan --> ApprovedPlan: user grants authority + ReadyPlan --> RejectedPlan: user rejects + ApprovedPlan --> SupersededPlan: newer revision approved + DraftPlan --> SupersededPlan: newer draft selected +``` + +Each revision contains: + +- Goal contract snapshot. +- Initial execution graph. +- Node contracts and evaluators. +- Expected artifacts and joins. +- Tool, model, skill, harness, and image versions. +- OSMO workflow previews where known. +- Expansion limits and approval triggers. +- Resource, token, spend, and time budgets. +- Risk summary, assumptions, and known unknowns. + +A running goal may have only one active approved revision. Work already dispatched under an older revision remains attributable to it and is reconciled by the transition policy. + +## Node lifecycle + +```mermaid +stateDiagram-v2 + [*] --> Proposed + Proposed --> Ready: contract admitted + Proposed --> Skipped: pruned + Ready --> Queued: dispatch selected + Ready --> NeedsApproval: authority missing + NeedsApproval --> Ready: approved + NeedsApproval --> Skipped: rejected + Queued --> Running: attempt starts + Running --> Waiting: dependency or backoff + Waiting --> Running: dependency available + Running --> Verifying: candidate result produced + Verifying --> Succeeded: node criteria pass + Verifying --> Ready: retry or revised attempt + Verifying --> Failed: recovery exhausted + Running --> Ready: retryable failure + Running --> Failed: terminal node failure + Proposed --> Canceled: stop propagation + Ready --> Canceled: stop propagation + Queued --> Canceled: stop propagation + Running --> Canceled: cancellation reconciled + Waiting --> Canceled: stop propagation + NeedsApproval --> Canceled: stop propagation +``` + +### Node invariants + +- A node cannot become `Ready` without a valid contract, dependency set, evaluator, budget allocation, and authority classification. +- A node cannot become `Running` without exactly one active attempt lease. +- A node cannot become `Succeeded` solely because a model or process returned success; its evaluator must accept the result. +- A terminal node retains all attempts, artifacts, messages, and evidence. +- Child creation is a proposal until the coordinator admits it under graph, policy, and budget limits. + +## Attempt lifecycle + +An attempt is the unit of dispatch and external idempotency. + +1. **Created**: Inputs, contract, authority, and idempotency key are frozen. +2. **Dispatching**: The coordinator claims a lease and starts a model harness, tool call, or OSMO submission. +3. **Executing**: The external runtime has acknowledged the attempt. +4. **Reconciling**: The coordinator observes outputs and terminal state, including after a crash. +5. **Succeeded**, **Failed**, **Canceled**, or **Unknown**: Terminal attempt outcome. + +`Unknown` means an external side effect may have happened but cannot yet be proven. The coordinator must reconcile by idempotency key, external identifier, or human review before retrying. + +## Parent, child, and join semantics + +- A parent owns the scope and budget delegated to its children. +- Child state does not directly overwrite parent state. +- Parents declare an explicit join policy: + - All required children succeed. + - Any one child succeeds. + - A quorum succeeds. + - An evaluator decides from available evidence. + - Best effort until deadline or budget exhaustion. +- Optional children may fail or be skipped without failing the parent. +- Required child failure returns control to the parent for retry, replacement, replan, partial completion, or terminal failure. +- Cancellation propagates from parent to descendants; descendant cancellation does not automatically propagate upward. +- Shared dependencies are represented as graph edges, not duplicated children. + +## Retry, restart, and replan + +These are different operations: + +- **Retry**: Repeat the same node contract and strategy with a new attempt. +- **Restart**: Recreate an execution capsule while reusing verified outputs where the runtime supports it. OSMO restart creates a new workflow rather than resuming the old one. +- **Replan**: Change dependencies, strategy, tools, resources, evaluator, or authority envelope in a new plan revision. + +Automatic retry is allowed only when: + +- The failure is classified as transient. +- The node contract and strategy remain unchanged. +- The authority envelope and retry budget permit it. +- Repeating the side effect is idempotent or safe. + +A material change always requires a revision. It may proceed automatically only when the existing approval explicitly authorizes that class of revision. + +## Pause and stop semantics + +OSMO has cancellation but no native workflow pause/resume. The goal-level UI must therefore use precise controls: + +- **Pause coordination** + - Acquire no new dispatch leases. + - Do not create or start new attempts. + - Active attempts and OSMO workflows continue. + +- **Stop pending work** + - Pause coordination. + - Cancel proposed, ready, and queued descendants. + - Let active attempts reach a terminal state. + +- **Stop everything** + - Pause coordination. + - Cancel all pending descendants. + - Send best-effort cancellation to active model, tool, and OSMO attempts. + - Reconcile until every descendant is terminal or explicitly marked unknown. + +The goal remains `Stopping` until reconciliation completes. The UI must not report `Stopped` immediately after a cancellation request. + +## Time and liveness + +Every nonterminal entity has: + +- A deadline or inherited deadline. +- A last-progress timestamp. +- A lease owner and lease expiry when actively coordinated. +- A next reconciliation time. +- A bounded waiting reason. + +The coordinator detects: + +- Expired dispatch leases. +- Attempts with no progress. +- Parents waiting on terminal children with no valid join path. +- Human decisions past their deadline. +- OSMO workflows missing from expected queries. +- Goals with no runnable node and no declared blocker. + +Detected liveness failures produce explicit events and recovery actions; they must not remain silent `Running` states. + +## Recovery and reconciliation + +The reconciler repeatedly compares desired goal state with: + +- Durable node and attempt records. +- Model harness run state. +- Tool idempotency records. +- OSMO workflow and task status. +- Approval decisions. +- Artifact and evaluator results. + +Reconciliation is at-least-once. All transition handlers must therefore be idempotent, and every external dispatch must have a stable client-generated key. + +## Lifecycle acceptance criteria + +- Every UI state has a precise durable counterpart. +- No terminal state has active descendants. +- No attempt can be dispatched twice under the same idempotency key. +- Coordinator restart reconstructs the same desired state from durable records. +- Material plan changes remain visible as revision diffs. +- Evaluation gates completion independently of execution success. +- Pause and stop actions behave exactly as described. +- Stalled goals are detected and surfaced within a defined reconciliation interval. diff --git a/projects/agents/03-ui.md b/projects/agents/03-ui.md new file mode 100644 index 000000000..ff8b02d26 --- /dev/null +++ b/projects/agents/03-ui.md @@ -0,0 +1,361 @@ + + +# Agentic Goals: User Interface + +Status: Draft + +## Product surface + +The initial experience is chat-first with a companion visual run console: + +- **Chat** captures intent, supports alignment, explains decisions, and accepts natural-language questions or steering. +- **Run console** is the durable operational view for plans, hierarchy, status, approvals, evidence, cost, and OSMO bindings. + +The first user is a technical individual running research or engineering goals. The UI should remain useful without requiring the user to adopt the internal agent or graph terminology. + +## UX principles + +- `/goal` always creates a draft. +- State-changing actions are visibly different from questions. +- Plans, approvals, and revisions are durable objects, not buried chat messages. +- Uncertainty is explicit; the UI does not invent exact progress or completion percentages. +- Deep hierarchies are navigated through outline and breadcrumbs, not rendered as one giant graph. +- Human attention is treated as a scarce resource and requested only with sufficient context. +- Evidence is easier to reach than raw agent narration. +- Existing OSMO workflow views remain the source for task-level DAG, logs, events, shell, and spec details. +- Every view has a shareable URL and can be reconstructed after refresh. + +## Entry point + +```text +/goal Train and evaluate a policy that meets the agreed benchmark +``` + +The immediate response: + +1. Creates a draft goal and stable goal URL. +2. Restates the objective and lists assumptions. +3. Shows a compact goal contract card. +4. Asks at most one high-value question at a time. +5. Performs no execution or external mutation. + +The user can continue in chat or open the goal console beside it. + +## Goal contract + +The goal contract remains visible throughout the run and contains: + +- Objective. +- Non-goals. +- Acceptance criteria and evaluator. +- Inputs and expected artifacts. +- Constraints and deadlines. +- Resource, token, and spend budgets. +- Permitted tools, models, skills, harnesses, data, and pools. +- Autonomy and approval policy. +- Delegation depth, fan-out, and concurrency limits. +- Known assumptions and unresolved decisions. + +The contract is editable while the goal is `Draft`. After approval, editing creates a plan revision and impact preview. + +## Primary journey + +### 1. Frame + +The chat leads a focused alignment conversation. The contract card updates as decisions are made and visibly distinguishes: + +- User-stated requirements. +- Lead-inferred assumptions. +- Defaults selected by policy. +- Unknowns that can be deferred. + +The user can correct any extracted item without rewriting the original prompt. + +### 2. Plan + +The lead presents: + +- A concise narrative of the approach. +- A collapsed outline of top-level workstreams. +- Dependencies and join conditions. +- Expected agent and deterministic execution. +- Expected OSMO workflow capsules. +- Acceptance checks and evidence requirements. +- Likely approval points. +- Cost, duration, and uncertainty ranges. + +Each plan is versioned. Selecting a node opens its contract without changing the chat scope. + +### 3. Preview + +“Preview” covers the complete agentic plan. “OSMO dry-run” refers only to rendered OSMO workflow YAML. + +The preview summarizes: + +- Initial graph and critical path. +- Expansion envelope. +- Models, tools, skills, harnesses, images, and versions. +- Credentials and authority required. +- OSMO pool, resource, quota, and validation results. +- Side effects and compensation strategy. +- Human decision points. +- Worst-case approved budget and deadline. +- Known unknowns and unvalidated future branches. + +The preview has one of three outcomes: + +- **Ready**: All required checks passed. +- **Needs input**: A material user decision is missing. +- **Blocked**: Policy, credentials, resources, validation, or another dependency prevents approval. + +### 4. Authorize + +The approval card names the exact scope being granted: + +- Plan revision. +- Allowed capabilities and side-effect classes. +- Maximum spend, compute, tokens, time, depth, fan-out, and concurrency. +- Permitted OSMO pools and resource classes. +- Actions that will still require human approval. + +Primary actions: + +- `Approve plan vN and run` +- `Revise` +- `Save draft` + +The first release should default to guardrailed autonomy: reads, model calls, local computation, and OSMO submissions may proceed inside the approved envelope; external writes, destructive actions, privilege expansion, policy exceptions, and budget increases require approval. + +### 5. Execute + +The lead posts updates only for: + +- A workstream beginning or finishing. +- A material plan revision. +- A blocker or failure that changes the critical path. +- A human decision. +- A budget, deadline, or risk threshold. +- Evaluation and terminal outcome. + +Routine tool calls and polling remain available in history but do not flood the main chat. + +### 6. Inspect and steer + +The user can select any workstream, node, agent run, attempt, artifact, or OSMO binding. + +Two explicit interaction modes avoid accidental mutation: + +- **Ask**: Read-only question about state, reasoning, evidence, or expected impact. +- **Direct**: Proposed instruction that may change desired state. + +A directive first shows whether it: + +- Fits the active authority envelope. +- Produces a plan revision. +- Invalidates completed work. +- Changes budget, deadline, tools, resources, or side effects. +- Requires a new approval. + +### 7. Verify and finish + +A goal enters `Evaluating` before `Completed`. + +The completion view includes: + +- Acceptance criteria with pass, fail, or unresolved status. +- Evidence and evaluator output for each criterion. +- Produced artifacts. +- OSMO workflow and task links. +- Plan deviations and human interventions. +- Time, token, compute, and spend summary. +- Remaining risks and recommended follow-up. + +The user may accept and close, reopen through a new revision, or save the plan as a reusable template. + +## Run console information architecture + +### Header + +- Goal title and status. +- Goal/run ID. +- Active plan revision. +- Elapsed time and deadline. +- Budget consumption and remaining envelope. +- Autonomy policy. +- Attention count. +- Pause and stop menu. + +### Main canvas + +The main view switches among: + +- **Outline**: Default hierarchical view for goals, workstreams, workers, and attempts. +- **Dependencies**: Cross-workstream data/control edges and joins. +- **Timeline**: Planned and actual execution, waits, approvals, retries, and critical path. + +The outline virtualizes and collapses deep hierarchies. The dependency view renders only the selected scope and immediate boundary edges. + +### Context panel + +The context panel contains persistent scoped chat and these tabs: + +- **Overview**: Contract, status, owner, budget, dependencies, and next action. +- **Plan**: Active node definition and relevant revision diff. +- **Evidence**: Claims, evaluator results, artifacts, and citations. +- **Runs**: Attempts, model/tool versions, and OSMO bindings. +- **Logs**: Agent, tool, or linked OSMO logs. +- **History**: Durable events, human decisions, and interventions. + +### Attention inbox + +Each item states: + +- Who or what is requesting attention. +- The decision needed. +- Why it is needed now. +- Available options. +- Supporting evidence. +- Impact of each option. +- Deadline and default behavior if unanswered. +- Whether the decision applies once, to one workstream, or to the remaining goal. + +The inbox separates blocking decisions from informational notifications. + +## Navigation and URL model + +Suggested routes: + +```text +/goals +/goals/{goal_id} +/goals/{goal_id}?node={node_id} +/goals/{goal_id}?node={node_id}&attempt={attempt_id} +/goals/{goal_id}?revision={revision_id} +/goals/{goal_id}?approval={approval_id} +``` + +Selecting hierarchy levels pushes browser history. Switching tabs or canvas modes replaces URL state. Scoped chat always displays its breadcrumb: + +```text +Goal / Workstream / Worker / Attempt +``` + +The existing OSMO UI already uses a graph-plus-resizable-inspector layout and URL-synchronized workflow/group/task navigation. Reuse those interaction patterns from [workflow-detail-layout.tsx](../../external/src/ui/src/features/workflows/detail/components/workflow-detail-layout.tsx) and [use-navigation-state.ts](../../external/src/ui/src/features/workflows/detail/hooks/use-navigation-state.ts). + +## OSMO integration + +Do not duplicate mature OSMO execution views. + +An OSMO-backed attempt should expose: + +- Workflow name, ID, pool, backend, priority, and status. +- Compact task status summary. +- Links to workflow DAG, task, logs, events, shell, spec, dashboard, Grafana, outputs, and datasets. +- Cancel or restart actions routed through goal-level policy and lifecycle semantics. + +Deep-link to the existing workflow detail view for task-level operations. Shell access is an expert intervention and must create an event in the goal history. + +## Status language + +Goal states: + +- `Draft` +- `Awaiting approval` +- `Running` +- `Waiting on user` +- `Evaluating` +- `Completed` +- `Blocked` +- `Failed` +- `Stopping` +- `Stopped` + +Node states: + +- `Proposed` +- `Ready` +- `Queued` +- `Running` +- `Waiting` +- `Needs approval` +- `Verifying` +- `Succeeded` +- `Failed` +- `Canceled` +- `Skipped` + +Do not map nondeterministic work to a percentage. Prefer: + +- Acceptance criteria passed. +- Milestones reached. +- Required joins completed. +- Critical blockers. +- ETA and cost ranges with confidence. + +## Pause and stop controls + +The menu must describe actual semantics: + +- **Pause coordination**: Start no new work; active work continues. +- **Stop pending work**: Cancel queued work; active work continues. +- **Stop everything**: Best-effort cancellation of all descendants. + +The UI enters `Stopping` until reconciliation confirms terminal descendants. It must not claim immediate cancellation. + +## Failure experience + +A failure card shows: + +- Failed node and attempt. +- User-visible impact. +- Evidence and relevant logs. +- Failure classification. +- Automatic action already taken. +- Remaining retry and budget allowance. +- Options: retry, revise, skip when permitted, inspect worker, open OSMO details, or stop. + +Transient retries within the approved envelope can happen silently except when they affect cost, deadline, or confidence. Strategy changes always appear as plan revisions. + +## Accessibility and operational quality + +- All graph information has an equivalent outline representation. +- Status is communicated through text and shape, not color alone. +- Approval and stop actions are keyboard accessible and require unambiguous focus. +- Streaming updates preserve reading position and announce only material changes. +- The UI remains usable with stale data and displays last reconciliation time. +- Large goals use pagination or virtualization for events, attempts, messages, and artifacts. +- Embedded logs keep their own filter state to avoid collisions with goal navigation. + +## First UX validation + +Validate one complete scenario: + +```text +/goal +→ one high-value clarification +→ editable goal contract +→ plan v1 +→ preview with two parallel workers and one OSMO capsule +→ scoped approval +→ live milestones +→ one nested approval +→ one recoverable failure +→ evidence-based completion +``` + +The UX is successful when the user can answer at every point: + +- What is happening? +- Why is it happening? +- What changed? +- What needs my attention? +- What evidence supports completion? +- What can I safely stop? diff --git a/projects/agents/04-lead-agent.md b/projects/agents/04-lead-agent.md new file mode 100644 index 000000000..242cf9a69 --- /dev/null +++ b/projects/agents/04-lead-agent.md @@ -0,0 +1,277 @@ + + +# Agentic Goals: Lead Agent + +Status: Draft + +## Role + +The lead agent is the user-facing planner, coordinator, and narrator for one goal. It helps the user define success, proposes a bounded organization of work, delegates to specialized workers, interprets results, and surfaces decisions. + +The lead is not the durable control plane. + +```mermaid +flowchart LR + User[User] <--> Lead["Lead agent"] + Lead -->|"proposals and commands"| Coordinator["Deterministic coordinator"] + Coordinator -->|"validated state view"| Lead + Coordinator <--> Store["Durable goal state"] + Coordinator <--> Policy["Policy engine"] + Coordinator --> Workers["Agent and deterministic runs"] + Coordinator --> OSMO["OSMO workflows"] +``` + +The lead may propose a plan, child, tool call, workflow, retry, or completion. The coordinator validates authority, state, budgets, graph invariants, and idempotency before applying the proposal. + +## Responsibilities + +### Goal framing + +- Convert `/goal` input into a draft goal contract. +- Separate explicit requirements from assumptions and defaults. +- Ask only questions that materially affect success, risk, time, cost, or authority. +- Define testable acceptance criteria and identify appropriate evaluators. +- Identify non-goals to prevent silent scope growth. + +### Planning + +- Decompose the goal into comprehensible workstreams. +- Distinguish delegation ownership from execution dependencies. +- Choose deterministic work when agent reasoning is unnecessary. +- Choose an OSMO workflow capsule only when the work benefits from cluster scheduling, isolation, data movement, accelerators, or long execution. +- Estimate cost, duration, uncertainty, and likely human decisions. +- Produce a plan that fits the active delegation and budget envelope. + +### Alignment and preview + +- Explain the plan in user language. +- Expose assumptions, alternatives, trade-offs, and unknowns. +- Describe what is known now versus what may be generated later. +- Present the initial graph and bounded expansion policy without claiming future branches have been dry-run. +- Summarize OSMO validation results for known workflow capsules. + +### Delegation + +- Select a worker by declared capability, policy, cost, context need, and evaluator fit. +- Write a precise child contract with scope, inputs, expected artifacts, budget, authority, deadline, and stop condition. +- Delegate only when specialization, parallelism, isolation, or context reduction outweighs coordination overhead. +- Avoid duplicating work already represented by an active node or artifact. +- Review child proposals before admitting further delegation. + +### Coordination + +- Track the critical path and joins through coordinator projections. +- React to material events, not raw polling noise. +- Classify failures as transient, strategy-related, policy-related, resource-related, or terminal. +- Propose retries only when the contract and strategy remain unchanged. +- Propose a plan revision for changed strategy, dependencies, tools, resources, side effects, or evaluation. +- Prevent one failed optional child from unnecessarily failing the complete goal. + +### Human interface + +- Keep the main thread focused on decisions and material progress. +- Surface approval requests with alternatives, evidence, impact, deadline, and default behavior. +- Route the user to a scoped worker conversation when detailed domain interaction is useful. +- Preserve an easy return path to the lead and summarize any nested decision. +- Explain pause, stop, retry, and replan effects before requesting action. + +### Evaluation and completion + +- Assemble candidate outputs and evidence. +- Invoke independent evaluators defined by the goal and node contracts. +- Map evaluator results to acceptance criteria. +- Propose remediation when criteria are not met and authority remains. +- Report completion only after the coordinator records accepted evaluation evidence. +- Summarize results, artifacts, deviations, interventions, spend, duration, and unresolved risks. + +## Non-responsibilities + +The lead must not: + +- Act as the source of truth for lifecycle state. +- Directly mutate the database, graph, policy, approval, or budget state. +- Bypass the coordinator to submit or cancel OSMO workflows. +- Grant itself broader authority, credentials, budget, or delegation rights. +- Treat model confidence as evidence. +- Approve its own high-risk actions. +- Declare success without an evaluator. +- Copy all child transcripts into its context. +- Depend on hidden conversational memory for recovery. +- Spawn workers merely to imitate an organizational hierarchy. +- Convert every tool call into an OSMO workflow. + +## Lead control loop + +```mermaid +flowchart TD + Observe["Observe durable projection"] --> Decide["Identify next material decision"] + Decide --> Propose["Propose plan, dispatch, question, or evaluation"] + Propose --> Validate["Coordinator validates"] + Validate -->|"accepted"| Wait["Wait for material event"] + Validate -->|"needs human"| Ask["Surface human decision"] + Validate -->|"rejected"| Revise["Revise proposal"] + Ask --> Observe + Wait --> Observe + Revise --> Observe +``` + +The lead runs when: + +- The user sends a message. +- A material goal event occurs. +- An approval or blocker is created. +- A join becomes satisfiable. +- Evaluation finishes. +- A liveness or budget threshold is crossed. + +It does not need to remain alive between events. Any model instance can resume from the durable projection and referenced artifacts. + +## Input projection + +The coordinator supplies a bounded, structured view: + +- Goal contract and active plan revision. +- Current goal status and next valid actions. +- Top-level execution outline and critical path. +- Open approvals, blockers, and deadlines. +- Budget allocation and consumption. +- Material events since the prior lead turn. +- Child summaries, artifact references, and evaluator results. +- OSMO workflow summaries and deep links. +- Relevant policy constraints and catalog entries. + +Raw logs, complete worker transcripts, and large artifacts remain out of context unless the lead explicitly requests a bounded excerpt or summary. + +## Lead outputs + +Lead outputs must use typed proposals rather than free-form side effects: + +- `ProposeGoalContract` +- `ProposePlanRevision` +- `RequestClarification` +- `ProposeNode` +- `ProposeDispatch` +- `ProposeRetry` +- `ProposeEvaluation` +- `RequestApproval` +- `ProposePause` +- `ProposeStop` +- `ProposeCompletion` +- `PostUserUpdate` + +Each proposal contains: + +- Goal, revision, node, and attempt references as applicable. +- Rationale. +- Expected state transition. +- Required authority and budget. +- Idempotency or deduplication key. +- Evidence references. +- User-visible summary. + +The coordinator rejects malformed, stale, unauthorized, or invariant-breaking proposals and returns a structured reason. + +## Planning strategy + +The lead should prefer the smallest useful organization. + +Before creating a child, it asks: + +1. Does this work have a distinct, testable output? +2. Does it require expertise, context, tools, isolation, or parallelism the parent lacks? +3. Is the expected value greater than delegation and join overhead? +4. Can the input and output be expressed as a stable contract? +5. Is there a clear evaluator and stop condition? +6. Does the remaining envelope permit it? + +If not, the lead handles the work directly or uses a deterministic step. + +## Worker selection + +The lead selects from immutable catalog snapshots. Selection considers: + +- Declared capability and supported artifact types. +- Tool and data access. +- Model quality, latency, cost, context, and policy class. +- Harness behavior and maximum runtime. +- Required compute and whether OSMO execution is appropriate. +- Historical evaluator performance for the task class. +- Data residency, confidentiality, and credential constraints. + +The lead may recommend a catalog change but cannot silently substitute an unapproved model, tool, skill, harness, or image. + +## Context management + +- Store source artifacts once and pass references. +- Require workers to return typed results, evidence, unresolved questions, and a compact summary. +- Build lead context from current state and material deltas, not full chronological history. +- Preserve provenance from each claim to the producing attempt and artifact. +- Summarize at workstream boundaries and invalidate summaries when their source artifacts are superseded. +- Mark untrusted content and prevent artifacts from silently becoming system instructions. + +## Plan revisions + +The lead creates a new revision when: + +- User intent or acceptance criteria change. +- Dependencies or workstream structure change. +- A new tool, model, skill, harness, image, pool, or resource class is needed. +- Side-effect or privilege scope expands. +- Budget or deadline changes. +- Completed work is invalidated. +- An evaluator or evidence requirement changes. + +The revision explains: + +- What changed and why. +- Which existing work remains valid. +- Which queued or active work should continue, drain, or stop. +- Cost, time, risk, and authority impact. +- Whether approval is required. + +## Failure behavior + +The lead must avoid both premature abandonment and unbounded recovery. + +- Transient failure: propose bounded retry. +- Invalid worker result: request remediation or replacement. +- Failed optional work: continue if join policy permits. +- Failed required work: revise strategy, request input, or declare blocker. +- OSMO failure: use status, events, logs, and artifacts to classify before restart or replan. +- Unknown side effect: do not retry until reconciliation or human review. +- Budget or deadline exhaustion: stop dispatching and surface alternatives. +- Lead model failure: preserve state and resume with another compatible lead instance. + +## Human communication style + +- Lead with outcome, blocker, or decision. +- Distinguish fact, inference, assumption, and recommendation. +- Use stable names for workstreams and artifacts. +- Avoid narrating every internal thought or tool call. +- Quantify cost and time as ranges when uncertainty is material. +- Explain why a human is needed and what happens without a response. +- Never obscure a material plan change inside a progress update. + +## Evaluation plan + +Evaluate the lead on complete goal traces, not isolated prompt quality: + +- Goal contracts capture stated intent without inventing constraints. +- Clarification count remains low without sacrificing correctness. +- Plans use deterministic work where appropriate. +- Delegation produces independently useful, testable outputs. +- Child creation remains inside depth, fan-out, budget, and authority limits. +- Required approvals are surfaced before side effects. +- Failure classification selects retry versus replan correctly. +- Context remains bounded as the graph grows. +- User updates are timely but not noisy. +- Completion claims match evaluator evidence. +- A replacement lead can resume from durable state without conversational loss. diff --git a/projects/agents/05-human-interfaces.md b/projects/agents/05-human-interfaces.md new file mode 100644 index 000000000..0e5b186e4 --- /dev/null +++ b/projects/agents/05-human-interfaces.md @@ -0,0 +1,349 @@ + + +# Agentic Goals: Human Interfaces + +Status: Draft + +## Purpose + +Define how a human aligns, authorizes, observes, steers, interrupts, and evaluates an agentic goal without becoming the manual scheduler for every nested worker. + +Human interaction is a first-class protocol. It is not an ad hoc pause in an agent transcript. + +## Principles + +- Ask for human attention only when it can change an outcome or authority. +- State exactly what decision is needed and why automation cannot make it. +- Bind approval to an immutable scope and plan revision. +- Distinguish questions from state-changing directives. +- Let the user inspect any nested scope without losing the lead context. +- Record manual interventions and their downstream impact. +- Define deadline and default behavior for every blocking request. +- Never treat silence as approval for a new side effect or expanded authority. +- Preserve a useful result when the user stops or abandons a partially completed goal. + +## Human interaction classes + +### Alignment + +Used while the goal is a draft: + +- Clarify objective or non-goals. +- Define acceptance criteria. +- Select among meaningful strategies. +- Set constraints, deadline, budget, and autonomy. +- Confirm inferred assumptions. +- Supply missing input or credentials. + +Alignment does not grant execution authority. + +### Approval + +Used when the system needs explicit authority: + +- Approve a plan revision and start execution. +- Permit an external write or irreversible action. +- Expand tool, model, data, credential, network, privilege, pool, or resource scope. +- Increase budget, deadline, delegation depth, fan-out, or concurrency. +- Accept a material strategy change. +- Authorize retry of an uncertain or non-idempotent side effect. +- Accept partial completion or waive an acceptance criterion. + +### Information request + +Used when the system needs domain input but not authority: + +- Choose a dataset or benchmark. +- Explain ambiguous source material. +- Resolve a business or scientific preference. +- Provide missing environmental context. + +### Notification + +Used for material but nonblocking updates: + +- Major milestone. +- Critical-path change. +- Automatic recovery that affects confidence, time, or cost. +- Approaching budget or deadline threshold. +- Evaluation result. +- Terminal outcome. + +### Intervention + +Initiated by the user: + +- Ask the lead or a worker for explanation. +- Add context or evidence. +- Propose a directive. +- Pause coordination. +- Stop pending work. +- Stop everything. +- Open an OSMO workflow, log, event, or shell. + +## Authority envelope + +Approval grants a bounded envelope, not general autonomy. + +An envelope records: + +- Goal and immutable plan revision. +- Effective user and approving identity. +- Allowed agent, model, skill, harness, tool, and image versions. +- Permitted data, repositories, services, network destinations, credentials, and OSMO pools. +- Allowed side-effect and risk classes. +- Spend, token, compute, time, depth, fan-out, concurrency, retry, and OSMO submission limits. +- Actions that always require additional approval. +- Expiration and revocation conditions. + +Suggested presets: + +### Supervised + +- Read-only reasoning and preview may proceed. +- Every model/tool dispatch, child creation, workflow submission, and mutation requires approval. + +### Guardrailed + +- Recommended initial preset. +- Reads, approved model calls, local computation, child creation, and OSMO submissions may proceed inside the envelope. +- External writes, destructive actions, privilege expansion, policy exceptions, uncertain retries, and envelope changes require approval. + +### Broad autonomy + +- Most actions inside the envelope proceed. +- Destructive actions, privilege expansion, policy exceptions, and envelope changes still require approval. +- Not required for the first validation. + +## Approval request contract + +Every approval request contains: + +- Stable approval ID. +- Requesting goal, workstream, node, and agent. +- Current plan revision and proposed revision when applicable. +- One concise decision statement. +- Reason the decision is needed now. +- Recommended option and alternatives. +- Evidence and relevant artifacts. +- Expected effect on outcome, cost, time, risk, and completed work. +- Exact authority to be granted. +- Whether the grant applies once, to one workstream, or to the remaining goal. +- Deadline. +- Safe default if unanswered. +- Idempotency key for the resulting action. + +Available decisions: + +- Approve once. +- Approve this class for the current workstream. +- Approve this class for the remaining goal within a displayed limit. +- Edit and approve. +- Reject. +- Defer. +- Ask a question without deciding. + +## Approval lifecycle + +```mermaid +stateDiagram-v2 + [*] --> Pending + Pending --> Approved: human approves + Pending --> Rejected: human rejects + Pending --> Deferred: human defers + Deferred --> Pending: reopened + Pending --> Expired: deadline passes + Pending --> Superseded: plan or state changes + Approved --> Consumed: action committed + Approved --> Revoked: human revokes before commit + Approved --> Superseded: bound state changes +``` + +An approval is consumed only when the authorized transition commits. A stale approval cannot authorize a changed plan, input, target, cost, or side effect. + +## Attention inbox + +The inbox is the canonical list of unresolved human requests. + +It separates: + +- **Blocking now**: No valid critical-path action can continue. +- **Blocking later**: Independent work continues, but a future join depends on the answer. +- **Review requested**: The system recommends inspection but can proceed under current authority. +- **Informational**: No decision required. + +Ordering considers: + +- Critical-path impact. +- Deadline. +- Cost of waiting. +- Risk. +- Number of descendants blocked. + +The lead batches compatible low-risk decisions where doing so does not obscure scope. + +## Chat scope + +Global chat addresses the lead. A user may enter a nested scope through `Talk to this worker`. + +Every scoped conversation displays: + +- Goal and workstream breadcrumb. +- Worker identity and contract. +- Current attempt and plan revision. +- Whether the worker is active, waiting, or terminal. +- `Return to lead`. + +The worker receives only the scoped message and relevant contract/artifact references. It does not inherit unrestricted authority from the user merely because the user opened its chat. + +When the user returns: + +- The nested conversation is summarized into a durable decision or context artifact. +- The lead receives the summary and any proposed plan change. +- Material directives still pass through coordinator and policy validation. + +## Ask versus Direct + +The composer has two explicit modes: + +### Ask + +- Read-only. +- May query state, reasoning, evidence, logs, expected impact, or alternatives. +- Cannot dispatch work, modify desired state, increase authority, or cancel execution. + +### Direct + +- Proposes a state-changing instruction. +- Shows affected scope before submission. +- Produces a plan diff or runtime action preview. +- States whether current authority is sufficient. +- Requires approval when the instruction exceeds the envelope. + +Natural language can suggest a mode, but the UI must make the final mode visible before committing. + +## Steering semantics + +Steering may: + +- Add context or an artifact. +- Change priority among ready nodes. +- Request a new workstream. +- Change strategy or evaluator. +- Replace a worker. +- Revise budget or deadline. +- Pause or stop a scope. + +The preview identifies: + +- Work that remains valid. +- Work invalidated or made obsolete. +- Active attempts that should continue, drain, or cancel. +- Added cost and time. +- New authority or human decisions. +- Revised acceptance criteria. + +Steering never edits historical plan revisions or attempt records. + +## Pause and stop + +Human controls use the lifecycle definitions from [02-lifecycle.md](02-lifecycle.md): + +- **Pause coordination**: Start no new work; active work continues. +- **Stop pending work**: Cancel queued work; active work continues. +- **Stop everything**: Best-effort cancel all descendants. + +Before commitment, show: + +- Number of pending and active nodes. +- Active OSMO workflows and whether their outputs may be lost. +- Non-cancelable or uncertain side effects. +- Estimated time to reconcile. +- Artifacts already preserved. + +The user may apply the action to one node, one workstream, or the whole goal. + +## Manual OSMO intervention + +The user may open existing OSMO workflow detail, logs, events, dashboards, or shell. + +- Read-only inspection requires no additional goal transition. +- Cancel, restart, resubmit, exec, port-forward, rsync, or shell commands are recorded as interventions. +- State-changing actions should be initiated through the goal console when possible so policy and lifecycle semantics remain consistent. +- If an action occurs directly in OSMO, the reconciler records external intervention and evaluates whether the plan is still valid. +- Shell access is considered an elevated expert action because it may alter workload state outside the declared node contract. + +## Notification policy + +Default delivery remains in the active chat and console. Optional external channels may notify for: + +- Blocking approval. +- Security or policy event. +- Budget or deadline threshold. +- Goal completion, failure, or stop. + +Notifications contain no secrets or large artifacts and link to the durable request. + +Users can configure: + +- Quiet hours. +- Severity threshold. +- Digest versus immediate delivery. +- Goal-specific overrides. +- Escalation target when a deadline approaches. + +Repeated polling or retry events are aggregated rather than emitted individually. + +## Unanswered requests + +Every request declares a safe default: + +- Continue independent work. +- Pause affected work. +- Reject the proposed action. +- Stop the affected scope. +- Escalate to another authorized human. + +No unanswered request defaults to expanded authority, destructive action, or irreversible side effect. + +When a request expires, the system records the default action and explains its impact in the lead conversation. + +## Conflicts and concurrency + +- Human decisions use optimistic concurrency against the plan revision and entity version. +- If state changes while an approval card is open, the card becomes stale and displays the replacement request. +- Conflicting directives from different authorized humans are resolved by explicit policy, not last-write-wins chat order. +- Revoking authority stops new dispatch immediately and reconciles active work according to the revocation policy. +- A human can override an agent recommendation but cannot bypass platform security or tenancy policy. + +## Trust and evidence + +Human-facing claims distinguish: + +- Observed fact. +- Tool or OSMO result. +- Agent inference. +- Assumption. +- Recommendation. + +Approval cards cite the source artifact or event. Untrusted artifact text is not rendered as an instruction. Sensitive inputs are redacted according to policy before entering model context, chat, notification, or audit views. + +## Acceptance criteria + +- No execution starts from `/goal` without a scoped approval. +- Every side effect can be traced to an envelope and actor. +- Stale approvals cannot authorize changed work. +- The user can inspect and converse with any worker while retaining a clear return to the lead. +- Questions cannot accidentally mutate state. +- Stop controls accurately describe and eventually reflect descendant state. +- Blocking requests always explain why a human is needed and what happens without a response. +- Notification volume remains bounded during long-running goals. +- Manual OSMO intervention is visible in goal history. diff --git a/projects/agents/06-workflow-construction.md b/projects/agents/06-workflow-construction.md new file mode 100644 index 000000000..25417a887 --- /dev/null +++ b/projects/agents/06-workflow-construction.md @@ -0,0 +1,316 @@ + + +# Agentic Goals: Workflow Construction + +Status: Draft + +## Purpose + +Define how the agent control plane turns an approved portion of the execution graph into a static, validated, attributable OSMO workflow capsule. + +The workflow constructor is a deterministic compiler and submission adapter. An agent may propose inputs to it, but an agent does not directly produce trusted executable YAML or bypass validation. + +## OSMO execution boundary + +Use an OSMO workflow capsule when work benefits from one or more of: + +- Kubernetes isolation. +- GPU or specialized resource scheduling. +- Multi-node or gang execution. +- Heterogeneous backend selection. +- Long-running computation. +- Large input or output movement. +- Checkpointing. +- Container-specific dependencies. +- OSMO-native logs, events, metrics, shell, or dashboards. + +Keep work in the agent control plane when it is: + +- Goal framing or planning. +- A lightweight model call. +- Approval routing. +- A low-latency API query. +- A small deterministic transformation. +- Coordinator reconciliation. +- Agent-to-agent message handling. + +Do not submit a workflow for every model turn or tool invocation. + +## Current OSMO constraints + +The constructor must compile to current OSMO semantics: + +- A workflow contains either tasks or groups; top-level tasks are normalized into one-task groups. +- Dependencies are static and represented through task inputs. +- Groups are the scheduling dependency unit. +- The complete graph is rendered and validated before submission. +- Jinja loops and conditionals expand at submission time, not at runtime. +- There is no native child-workflow node or in-flight graph expansion. +- There is no runtime branch or general runtime loop primitive. +- Pool and backend placement are fixed when submitted. +- Workflow pause/resume is not available. +- Cross-workflow task inputs require the referenced prior task to be finished. +- Restart creates a new workflow and may reuse completed outputs. +- Workflow and per-user task limits constrain capsule size; the default workflow task cap is currently 20. + +See [WorkflowSpec](../../external/src/utils/job/workflow.py), [TaskSpec and TaskGroupSpec](../../external/src/utils/job/task.py), [submission](../../external/src/service/core/workflow/workflow_service.py), and [DAG materialization](../../external/src/utils/job/jobs.py). + +## Compiler inputs + +The constructor receives an immutable `WorkflowConstructionRequest`: + +- Goal, plan revision, node, and attempt IDs. +- Approved execution subgraph. +- Node contracts and dependency edges. +- Resolved input artifacts and immutable versions. +- Selected tool, agent, model, harness, and container image manifests. +- OSMO pool, priority, resource, timeout, credential, and data policies. +- Output artifact contracts and evaluators. +- Authority envelope. +- Client-generated submission idempotency key. + +No mutable chat transcript or ambient environment is an implicit compiler input. + +## Compiler output + +The deterministic result contains: + +- Canonical OSMO workflow template. +- Fully rendered dry-run spec. +- Validation result. +- Input and output binding manifest. +- Goal-to-workflow node mapping. +- Required credentials and policy decisions. +- Resource and quota summary. +- Expected cost and time range. +- Source hashes and compiler version. +- Submission idempotency key. + +The canonical result is stored before submission and is immutable for the attempt. + +## Construction pipeline + +```mermaid +flowchart LR + Select["Select approved subgraph"] --> Freeze["Freeze inputs and manifests"] + Freeze --> Partition["Partition execution capsules"] + Partition --> Compile["Compile OSMO template"] + Compile --> DryRun["Render dry-run"] + DryRun --> Validate["OSMO and policy validation"] + Validate --> Record["Record immutable construction"] + Record --> Submit["Idempotent submit"] + Submit --> Bind["Bind OSMO workflow ID"] + Bind --> Reconcile["Reconcile status and artifacts"] +``` + +### 1. Select + +Choose a connected, ready portion of the approved execution graph whose dependencies are satisfied or can be represented inside one static OSMO DAG. + +### 2. Freeze + +Resolve and pin: + +- Input artifact versions and checksums. +- Images and digests. +- Tools, models, skills, and harness versions. +- Commands, arguments, environment, and files. +- Credentials by reference. +- Pool, resource, timeout, priority, retry, checkpoint, and output policy. + +### 3. Partition + +Split capsules at boundaries such as: + +- Different OSMO pools or backends. +- Different security or credential scopes. +- Human approval gates. +- Runtime-discovered fan-out. +- Dynamic agent replanning. +- Cross-region or data residency constraints. +- Distinct failure or cancellation domains. +- Task count and quota limits. +- Long waits that should not occupy a workflow. + +Prefer one capsule when tasks form a stable, data-connected DAG and benefit from one submission. Prefer separate capsules when coordination is dynamic or lifecycle ownership differs. + +### 4. Compile + +Generate a canonical OSMO template using only schema-supported fields. Generated names must be deterministic, Kubernetes-safe, and traceable to goal entities without exposing sensitive content. + +### 5. Render and validate + +Use OSMO dry-run to render Jinja and variables, then validation-only mode to check workflow structure, pool, resources, credentials, registries, quotas, and platform constraints. + +Agentic preview and OSMO dry-run remain distinct: + +- Agentic preview describes the known plan and expansion envelope. +- OSMO dry-run validates one known static capsule. + +### 6. Record + +Persist the template, rendered spec, validation result, hashes, bindings, and authority decision before creating external side effects. + +### 7. Submit idempotently + +OSMO submission does not expose a general client idempotency key. The control plane therefore maintains a submission ledger: + +- Reserve one idempotency key transactionally. +- Submit at most one workflow for that key. +- Record the returned workflow name and UUID. +- On ambiguous failure, reconcile by stored response, deterministic metadata, or operator review before retrying. +- Never create a second attempt under the same key. + +### 8. Reconcile + +Poll OSMO workflow state, logs, events, and task outputs. Convert OSMO state into attempt events without treating transient query failure as workflow failure. + +## Capsule granularity + +A capsule should be large enough to amortize Kubernetes and OSMO scheduling overhead but small enough to preserve: + +- Independent retry and cancellation. +- Clear artifact contracts. +- Security boundaries. +- Human approval boundaries. +- Dynamic replanning points. +- Resource placement. +- Understandable failure impact. + +Candidate heuristics: + +- Combine stable deterministic producer/consumer tasks in one capsule. +- Keep runtime agent decision boundaries outside a static capsule unless the complete bounded loop intentionally runs inside one container. +- Do not combine tasks that require different pools. +- Do not hold a capsule open waiting for a human decision. +- Avoid a capsule whose failure would force unrelated completed work to rerun. + +## Mapping node classes + +### Deterministic job + +Compile directly to an OSMO task when cluster execution is warranted. + +- Typed inputs become task or URL inputs. +- Command and arguments come from a pinned tool manifest. +- Outputs are written to `{{output}}` and registered as artifacts. +- Exit actions handle known process codes. + +### Bounded agent run + +Two execution modes are possible: + +1. **Control-plane agent** + - Preferred for planning, lightweight tools, and rapid interaction. + - May submit separate OSMO capsules through coordinator proposals. + +2. **OSMO-hosted agent** + - Used when the agent requires GPU inference, specialized dependencies, data locality, strong isolation, or long execution. + - Runs a complete bounded harness in one OSMO task or stable task group. + - Returns proposals and artifacts to the coordinator; it does not gain unrestricted OSMO credentials. + +### Constrained agent-tool loop + +Package the harness and approved deterministic tools into a pinned image when execution locality justifies OSMO. Keep dynamic child creation in the external coordinator. + +## Dependencies and artifacts + +### Inside one workflow + +Use task inputs for both data handoff and scheduling dependencies. The producer writes to its output directory; OSMO transfers the output to the consumer. + +### Across workflows + +The coordinator waits for the producer artifact to become durable and verified before constructing the consumer capsule. It may reference the completed prior task output or a stable external URL/dataset. + +Do not use an unfinished cross-workflow reference as a substitute for external coordination. + +### Non-data dependencies + +OSMO task inputs couple dependency and data movement. If a dependency carries no artifact, the constructor should use a small manifest artifact or split the work into separate capsules coordinated externally rather than inventing unsupported control edges. + +## Groups + +An OSMO group is a gang-scheduled set of tasks, not an agent team or hierarchy. + +Use a group only when tasks must start and execute together, such as distributed training or tightly coupled services. Define the lead task and barrier behavior deliberately; do not map every delegated workstream to a group. + +## Generated workflow shape + +Illustrative output: + +```yaml +version: 2 +workflow: + name: goal-abc-node-def-attempt-01 + timeout: + exec: 4h + queue: 1h + tasks: + - name: execute + image: registry.example/approved-tool@sha256:... + command: ["/app/run"] + args: ["--input", "{{input:0}}", "--output", "{{output}}"] + inputs: + - url: s3://approved-artifacts/input-version + outputs: + - url: s3://approved-artifacts/goal-abc/node-def/attempt-01 + environment: + GOAL_RUN_ID: goal-abc + NODE_RUN_ID: node-def + ATTEMPT_ID: attempt-01 +``` + +Goal metadata in environment variables is for traceability, not authorization. The coordinator remains the source of authority. + +## Failure and retry + +- Map OSMO terminal status to an attempt result, not directly to goal result. +- Use task reschedule only for known transient process outcomes and configured retry limits. +- Use OSMO restart when the same workflow strategy should rerun while reusing completed outputs. +- Generate a new construction request for changed strategy, resources, tools, graph, or outputs. +- Treat cancellation as best effort until OSMO reports a terminal state. +- Preserve logs, events, rendered spec, and partial artifact references for diagnosis. + +## Security + +- Accept only cataloged image digests and tool manifests. +- Validate `privileged`, `hostNetwork`, mounts, credentials, and network needs against policy. +- Pass credentials by reference and least-privilege injection; never place secret values in generated YAML, prompts, or environment manifests stored as evidence. +- Do not grant an OSMO-hosted agent a general user token when a scoped callback or capability token suffices. +- Redact rendered specs and logs before exposing them to models. +- Sign or hash the canonical construction to detect post-approval changes. + +## Observability and lineage + +Record: + +- Goal, plan, node, and attempt IDs. +- Constructor and schema versions. +- Template and rendered-spec hashes. +- Input and image digests. +- Validation and policy results. +- Submission idempotency key. +- OSMO workflow name, UUID, pool, backend, and task mapping. +- Status transitions. +- Logs, events, outputs, and evaluator references. +- Cancel, restart, resubmit, exec, shell, or other interventions. + +## Acceptance criteria + +- The same frozen request produces byte-equivalent canonical output. +- No unvalidated workflow can be submitted. +- Every OSMO workflow maps to exactly one attempt and authority envelope. +- Ambiguous submission does not create duplicate workflows. +- Dynamic agent decisions occur outside static OSMO DAGs. +- Cross-workflow consumers cannot start before required artifacts are durable and verified. +- Security-sensitive fields are policy-checked and provenance is retained. +- OSMO failure, restart, and cancellation remain attempt-level events rather than bypassing goal lifecycle. diff --git a/projects/agents/07-agent-construction.md b/projects/agents/07-agent-construction.md new file mode 100644 index 000000000..d83554d3d --- /dev/null +++ b/projects/agents/07-agent-construction.md @@ -0,0 +1,363 @@ + + +# Agentic Goals: Agent Construction + +Status: Draft + +## Purpose + +Define how a catalog of models, tools, skills, harnesses, images, policies, and evaluators becomes one immutable, bounded agent run. + +An agent is not merely a model plus a prompt. It is a versioned execution contract with enforceable capabilities, limits, inputs, outputs, and evaluation. + +## Agent definition + +An agent definition contains: + +- Stable name, version, owner, and purpose. +- Declared capabilities and task classes. +- Accepted input artifact schemas. +- Required output artifact schemas. +- Model selection policy. +- Harness and prompting strategy. +- Tool and skill allowlist. +- Execution environment and optional image. +- Context assembly and memory policy. +- Delegation policy. +- Authority and credential requirements. +- Step, token, spend, compute, and wall-time limits. +- Stop conditions. +- Failure and retry behavior. +- Evaluators. +- Security and data-handling classification. + +Agent definitions are immutable after publication. Changes produce a new version. + +## Agent run construction + +```mermaid +flowchart LR + Contract["Node contract"] --> Select["Select agent definition"] + Catalog["Catalog snapshot"] --> Select + Select --> Resolve["Resolve model, tools, skills, harness, image"] + Resolve --> Context["Assemble bounded context"] + Context --> Policy["Policy and authority validation"] + Policy --> Freeze["Freeze AgentRunSpec"] + Freeze --> Execute["Execute bounded harness"] + Execute --> Evaluate["Validate result"] + Evaluate --> Record["Record artifacts and evidence"] +``` + +The deterministic constructor produces an immutable `AgentRunSpec`. The model does not select or mutate its own enforcement limits after execution begins. + +## AgentRunSpec + +Each run freezes: + +- Goal, plan revision, node, and attempt IDs. +- Agent definition and catalog snapshot versions. +- Input contracts, artifact references, checksums, and trust labels. +- Expected output and evidence schemas. +- Selected model and parameters. +- Harness version and system instructions. +- Tool and skill manifests. +- Capability and credential tokens. +- Execution placement. +- Delegation allowance. +- Step, token, spend, compute, and time budgets. +- Stop conditions and deadlines. +- Evaluator definitions. +- Idempotency and correlation IDs. + +The run spec is stored before model execution. + +## Node contract + +Every agent begins with a node contract containing: + +- One bounded sub-goal. +- Why the work exists and how it contributes to the parent. +- Explicit non-goals. +- Typed inputs. +- Expected output artifacts. +- Acceptance criteria. +- Permitted tools, data, and side effects. +- Delegation allowance. +- Budget and deadline. +- Required human approvals. +- Join or handoff target. + +If the contract is ambiguous enough to change execution materially, the agent returns a clarification request instead of silently expanding scope. + +## Model selection + +Model selection is policy-driven and frozen per attempt. + +Selection may consider: + +- Capability and evaluator performance for the task class. +- Context size and modality. +- Tool-calling support. +- Latency and cost. +- Data confidentiality and residency. +- Availability and rate limits. +- Required reasoning depth. +- Execution environment. + +The agent may recommend escalation to another model, but the coordinator validates availability, policy, and budget before creating a new attempt. + +Model output is always treated as nondeterministic. Temperature or a deterministic harness does not make the complete agent deterministic. + +## Harness + +The harness controls the agent loop: + +1. Load the frozen run spec and bounded context. +2. Ask the model for a typed next action. +3. Validate the action against state, schema, capability, policy, and remaining budget. +4. Execute an approved read, tool call, proposal, or response. +5. Record the action, result, cost, and evidence reference. +6. Update bounded working context. +7. Stop on accepted output, clarification, approval, delegation proposal, budget/deadline, cancellation, or unrecoverable failure. + +The harness, not the prompt, enforces: + +- Maximum steps. +- Tool allowlist. +- Argument schemas. +- Timeouts. +- Output size. +- Token and spend limits. +- Delegation bounds. +- Side-effect gating. +- Cancellation. + +## Agent classes + +### Lead agent + +Defined in [04-lead-agent.md](04-lead-agent.md). It receives a goal-level projection, proposes plans and coordination actions, and communicates with the user. + +### Worker agent + +Owns one bounded node contract and returns a typed result, evidence, clarification, approval request, or child proposal. + +### Evaluator agent + +Judges a candidate artifact against explicit criteria. It must not be the same run that produced the candidate when independent evaluation is required. + +### Specialist agent + +Provides domain-specific analysis or tool operation under a narrow capability set. Specialization should reduce context and authority, not merely change persona wording. + +## Tools + +Every tool manifest declares: + +- Stable name and version. +- Description and capability class. +- Typed input and output schemas. +- Read or side-effect classification. +- Idempotency support. +- Compensation behavior. +- Authentication and credential scope. +- Network, filesystem, and environment needs. +- Timeout and output limits. +- Data sensitivity constraints. +- Execution location. +- Audit and redaction rules. + +Model-generated arguments are schema-validated. High-risk arguments may require deterministic policy checks or human approval even when the tool itself is allowlisted. + +## Skills + +A skill is reusable procedural guidance and supporting resources, not an authority grant. + +- Pin skill version in the run spec. +- Treat skill instructions as lower priority than platform policy and the node contract. +- Declare the tools and side effects a skill expects. +- Evaluate skill behavior with representative traces. +- Do not let a skill silently widen tool, credential, data, or delegation access. +- Keep skill content out of context unless selected for the current task. + +The existing OSMO Agent Skills demonstrate resource selection, workflow generation, submission, monitoring, diagnosis, and retries outside OSMO core. See [external/skills](../../external/skills/README.md). + +## Context construction + +Context is assembled from durable references: + +- Node contract. +- Relevant goal contract subset. +- Active plan revision subset. +- Typed input artifacts. +- Parent handoff. +- Applicable policy. +- Tool and skill instructions. +- Material prior-attempt summary when retrying. + +Avoid: + +- Full goal event history. +- Complete parent or sibling transcripts. +- Unbounded logs. +- Duplicate large artifacts. +- Secrets not required by the model. +- Treating artifact content as trusted system instructions. + +Context artifacts carry provenance and trust labels. Large data is accessed through tools or OSMO inputs rather than copied into the prompt. + +## Memory + +Working memory is attempt-local and disposable. + +Durable memory consists only of explicit artifacts: + +- Result. +- Evidence. +- Summary. +- Open questions. +- Learned constraints. +- Reusable domain knowledge approved for future use. + +Agents do not retain hidden cross-goal memory. Any memory reused across runs is versioned, attributable, policy-filtered, and visible to the user or administrator. + +## Delegation + +An agent may propose a child only when its run spec permits delegation. + +The proposal includes: + +- Child sub-goal and non-goals. +- Expected output and evaluator. +- Inputs and artifact references. +- Requested agent capability. +- Tool, authority, resource, and credential needs. +- Budget and deadline allocation. +- Parent join policy. +- Rationale for delegation. + +The coordinator checks depth, fan-out, concurrency, duplication, cycle risk, authority, policy, and remaining parent budget. Accepted children receive a fraction of the parent envelope; authority is never implicitly inherited in full. + +## OSMO execution placement + +An agent may run: + +- In the agent control plane for low-latency reasoning and lightweight tools. +- In an isolated service runtime. +- As an OSMO-hosted agent task when it needs accelerator inference, data locality, specialized dependencies, long runtime, or stronger workload isolation. + +An OSMO-hosted agent: + +- Runs a complete bounded harness. +- Receives scoped inputs and capability tokens. +- Emits typed results and proposals. +- Does not directly mutate the goal graph. +- Does not receive unrestricted user or OSMO credentials. +- Uses the workflow construction path in [06-workflow-construction.md](06-workflow-construction.md). + +## Result envelope + +Every worker terminates with exactly one typed outcome: + +- `Completed` +- `NeedsClarification` +- `NeedsApproval` +- `ProposeChildren` +- `RetryableFailure` +- `TerminalFailure` +- `Canceled` + +A successful result contains: + +- Output artifacts. +- Compact summary. +- Evidence references. +- Acceptance-criterion mapping. +- Assumptions and uncertainty. +- Unresolved questions. +- Suggested follow-up. +- Token, cost, time, and tool-use accounting. + +Free-form text may accompany the envelope but cannot replace required fields. + +## Evaluation + +Evaluators may be: + +- Deterministic tests. +- Schema and invariant checks. +- Artifact comparisons. +- OSMO workflow or benchmark runs. +- Model-based judges with calibrated criteria. +- Human review. +- Combinations of the above. + +Prefer deterministic evidence whenever available. Model-based evaluation must record its model, rubric, inputs, output, and uncertainty. + +An agent cannot be the sole evaluator of its own high-impact result. + +## Failure and retry + +- Harness or infrastructure failure may retry the same frozen run spec. +- Invalid model output may be repaired within the same step budget. +- Tool failure is classified before retry. +- Changed model, tool, strategy, context, or evaluator creates a new attempt. +- Unknown external side effect blocks automatic retry. +- Budget exhaustion returns a bounded failure or escalation request. +- Cancellation must interrupt model streaming and prevent new tool dispatch. + +## Security and supply chain + +- Pin images by digest and catalog entries by immutable version. +- Verify signatures where available. +- Issue short-lived, least-privilege capability tokens. +- Separate model-visible context from tool-held secrets. +- Sandbox filesystem and network access. +- Redact logs and artifacts before model ingestion. +- Treat tool output, retrieved documents, and child messages as untrusted data. +- Record all model, tool, skill, harness, image, policy, and evaluator versions. +- Prevent an agent from editing its own manifest, policy, evaluator, or budget. + +## Example manifest shape + +```yaml +name: workflow-investigator +version: 1 +purpose: Diagnose one failed OSMO workflow and return evidence-backed recovery options. +inputs: + - workflow-binding/v1 +outputs: + - diagnosis/v1 +modelPolicy: technical-reasoning +harness: bounded-tool-loop/v1 +tools: + - osmo-workflow-read/v1 + - osmo-logs-read/v1 +delegation: + allowed: false +limits: + steps: 20 + wallTime: 15m + spend: 2.00 +sideEffects: none +evaluator: diagnosis-evidence-check/v1 +``` + +## Acceptance criteria + +- Every run can be reconstructed from an immutable spec. +- Agents cannot exceed tool, authority, delegation, or budget limits through prompting. +- Inputs and outputs are typed and attributable. +- Context remains bounded as the goal grows. +- A replacement runtime can resume from durable artifacts without hidden memory. +- Agent-created children are admitted by the coordinator rather than executed implicitly. +- Model, tool, skill, harness, image, and evaluator versions are recorded. +- Completion requires evaluator evidence. diff --git a/projects/agents/08-agent-agent-communication.md b/projects/agents/08-agent-agent-communication.md new file mode 100644 index 000000000..e74a80c8c --- /dev/null +++ b/projects/agents/08-agent-agent-communication.md @@ -0,0 +1,404 @@ + + +# Agentic Goals: Agent-to-Agent Communication + +Status: Draft + +## Purpose + +Define durable, typed communication among the lead, workers, evaluators, deterministic processes, and OSMO-hosted agents. + +Agents do not communicate through invisible shared context or unrestricted peer-to-peer chat. They exchange messages and artifacts through the coordinator so communication remains attributable, bounded, policy-checked, and recoverable. + +## Principles + +- Artifacts carry substantive data; messages carry intent and references. +- Every message has a sender, recipient, purpose, contract, and correlation ID. +- Delivery is at-least-once, so consumers must be idempotent. +- Authority is never transferred by prose. +- Parent/child ownership and execution dependencies remain separate. +- Messages are untrusted input to the receiving agent. +- Communication volume is budgeted and backpressured. +- Human-visible summaries are derived from durable messages and artifacts. +- OSMO logs or task output are not an agent messaging protocol. + +## Communication topology + +The first validation supports: + +- Lead to worker. +- Worker to lead or parent. +- Parent to child. +- Evaluator to the node being evaluated through coordinator state. +- Coordinator broadcasts of cancellation, revision, or authority changes. +- Explicit sibling exchange only through an approved shared artifact or coordinator-routed request. + +```mermaid +flowchart TD + Lead["Lead agent"] <--> Bus["Coordinator message service"] + Parent["Parent worker"] <--> Bus + ChildA["Child worker A"] <--> Bus + ChildB["Child worker B"] <--> Bus + Evaluator[Evaluator] <--> Bus + Bus <--> Artifacts["Artifact store"] + Bus <--> Events["Event ledger"] +``` + +Unrestricted mesh communication is intentionally excluded. It complicates authority, creates hidden dependencies, and makes completion and cancellation difficult to reason about. + +## Message envelope + +Every message includes: + +- Message ID. +- Goal and plan revision IDs. +- Sender and recipient entity IDs. +- Sender attempt ID. +- Message type and schema version. +- Conversation or delegation ID. +- Correlation and causation IDs. +- Sequence number within the conversation. +- Creation time and optional expiry. +- Priority. +- Human-visibility classification. +- Authority requirement. +- Artifact references. +- Typed payload. +- Idempotency key. +- Integrity metadata. + +Messages are immutable after publication. Corrections reference and supersede prior messages. + +## Message types + +### DelegationRequest + +Parent proposes a child contract: + +- Sub-goal and non-goals. +- Input artifact references. +- Expected output and evaluator. +- Requested capabilities. +- Budget, deadline, and authority allocation. +- Join policy. +- Rationale. + +The coordinator admits or rejects the proposal before a child exists. + +### DelegationAccepted + +Confirms: + +- Child node and run IDs. +- Frozen contract. +- Allocated envelope. +- Expected delivery schema. +- Cancellation and deadline semantics. + +### WorkDirective + +Sends approved desired work to an existing agent. A directive cannot silently modify the frozen contract; material changes create a new attempt or plan revision. + +### Query + +Requests bounded information or analysis from another scope without changing desired state. + +### Response + +Answers a query with typed content and artifact references. + +### Progress + +Reports a material milestone, blocker, changed estimate, or heartbeat. Routine internal steps remain in attempt history rather than producing cross-agent messages. + +### Result + +Returns: + +- Outcome type. +- Output artifacts. +- Evidence. +- Acceptance mapping. +- Summary. +- Assumptions and uncertainty. +- Unresolved questions. +- Accounting. + +### ClarificationRequest + +Requests missing information needed to satisfy the contract. The parent may answer, route to the lead, or create a human request. + +### ApprovalRequest + +Proposes an action outside current authority. The coordinator turns it into the human approval protocol from [05-human-interfaces.md](05-human-interfaces.md). + +### ChildProposal + +Requests further delegation. It is not executable until coordinator admission. + +### Cancel + +Revokes desired execution for a scope. Recipients acknowledge and stop new work before reconciling active operations. + +### RevisionNotice + +Informs affected agents that a new plan revision changes, supersedes, or invalidates their work. + +### EvaluationResult + +Records criterion-level pass, fail, or unresolved outcomes with evidence and rubric version. + +## Artifacts + +Messages reference artifacts rather than embedding large payloads. + +Every artifact has: + +- Stable artifact ID and version. +- Type and schema version. +- Producing goal, node, and attempt. +- Content checksum. +- Storage location. +- Size and media type. +- Trust and sensitivity labels. +- Retention policy. +- Access policy. +- Supersession relationship. +- Human-readable summary when useful. + +Examples: + +- Goal contract. +- Plan revision. +- Dataset manifest. +- Source bundle. +- Model checkpoint. +- Analysis report. +- OSMO workflow binding. +- Tool result. +- Evidence bundle. +- Worker summary. +- Evaluation report. + +Consumers verify schema, integrity, access, and trust classification before use. + +## Handoffs + +A parent-to-child handoff contains only what the child needs: + +- Frozen child contract. +- Relevant goal context. +- Referenced inputs. +- Constraints and policy. +- Expected output. +- Parent join semantics. +- Escalation route. + +A child-to-parent handoff contains: + +- Typed result. +- Evidence and artifacts. +- Compact summary. +- Assumptions. +- Uncertainty. +- Unresolved questions. +- Recommended next action. + +Raw child transcript is retained for audit according to policy but is not automatically injected into the parent context. + +## Conversations + +A conversation is a durable ordered stream associated with one goal scope and purpose. + +Conversation classes: + +- Lead and user. +- Parent and child. +- Query and response. +- Human and nested worker. +- Evaluator clarification. + +Per-conversation sequence numbers preserve local order. Global ordering across independent conversations is not assumed; causation IDs establish meaningful relationships. + +## Delivery semantics + +- Persist message before delivery. +- Deliver at least once. +- Acknowledge processing with the consumer attempt and message ID. +- Deduplicate by message ID and idempotency key. +- Retry transient delivery failure with bounded backoff. +- Move permanently invalid messages to a visible rejected state with reason. +- Expired messages do not trigger new work. +- Cancellation and authority revocation have higher priority than normal work. + +Exactly-once model or tool execution is not assumed. External actions use their own idempotency and reconciliation records. + +## Ordering and stale messages + +Before acting, a consumer validates: + +- Plan revision is still applicable. +- Node and attempt are current. +- Sender was authorized to send the message. +- Recipient contract accepts the message type. +- Referenced artifacts are still valid. +- Deadline has not passed. + +A stale message is recorded and ignored or transformed into a clarification; it never silently mutates current state. + +## Joins and aggregation + +Parents do not wait on chat completion. They wait on durable child terminal states and declared artifacts. + +Supported join policies: + +- All required children. +- Any successful child. +- Quorum. +- Best effort until budget or deadline. +- Evaluator decides from available evidence. + +The aggregator: + +- Validates child result schemas. +- Detects conflicting claims. +- Deduplicates shared artifacts. +- Preserves provenance. +- Produces a bounded parent summary. +- Requests adjudication when conflicts affect acceptance criteria. + +## Conflict handling + +When agents disagree: + +1. Preserve both claims and evidence. +2. Determine whether the disagreement affects the parent contract. +3. Apply a deterministic rule or evaluator when defined. +4. Create a focused adjudication node when additional work is justified. +5. Route to a human when policy, values, or irreducible ambiguity requires it. + +The lead must not erase disagreement by selecting the most fluent response. + +## Authority and credentials + +- Messages carry references to authority, never bearer secrets. +- A parent can allocate only a subset of its delegable envelope. +- A child cannot expand scope by requesting it from a sibling. +- Tool capability tokens are issued directly by the coordinator for one run and scope. +- Recipients verify effective authority at action time, not only message creation time. +- Revocation prevents new actions even if old messages remain queued. + +## Security and trust + +- Treat every message and artifact body as untrusted data. +- Keep policy and system instructions outside user-controlled artifacts. +- Mark externally retrieved or model-generated content. +- Scan and redact secrets before model exposure or human notification. +- Enforce artifact access independently of message routing. +- Sign or integrity-check messages crossing execution boundaries. +- Limit links and network destinations to approved schemes and domains. +- Record provenance for summaries so users can inspect original evidence. + +## Communication budgets + +Each run has limits for: + +- Messages sent. +- Queries to siblings or parent. +- Child proposals. +- Total embedded payload bytes. +- Artifact reads. +- Progress update frequency. +- Model tokens consumed by communication. + +The coordinator applies backpressure: + +- Coalesce routine progress. +- Reject duplicate questions. +- Prefer artifact summaries over repeated raw reads. +- Rate-limit noncritical communication. +- Prioritize cancellation, approval, blocker, and terminal result messages. + +## Liveness + +Messages that require a response declare: + +- Response schema. +- Deadline. +- Retry policy. +- Escalation target. +- Safe default. + +The coordinator detects: + +- Unacknowledged directives. +- Children with no material progress. +- Parents waiting on messages instead of declared joins. +- Expired clarification or approval requests. +- Orphan conversations after plan revision or cancellation. + +Agents use bounded progress heartbeats only for liveness; heartbeats do not imply useful progress. + +## OSMO-hosted agents + +OSMO-hosted agents communicate with the coordinator through a scoped callback or message API: + +- The workflow task receives goal, node, attempt, and callback identifiers. +- Authentication is short-lived and limited to the current run. +- Messages are persisted by the external control plane. +- Large outputs are uploaded as artifacts and referenced in result messages. +- Loss of the callback path causes bounded retry and eventual attempt failure or reconciliation. +- The task does not use OSMO logs, Redis internals, or unrestricted user credentials as a substitute for the protocol. + +## Human visibility + +Messages declare one visibility level: + +- Hidden operational record. +- Available in history. +- Summarized by the lead. +- Requires immediate human attention. + +The lead may summarize but cannot change the underlying message or evidence. A human entering a nested worker conversation creates messages in that scoped conversation; any state-changing directive still goes through coordinator validation. + +## Example result message + +```json +{ + "type": "Result", + "schemaVersion": 1, + "messageId": "msg-123", + "goalId": "goal-abc", + "planRevisionId": "plan-3", + "senderAttemptId": "attempt-7", + "recipientNodeId": "node-parent", + "conversationId": "delegation-42", + "outcome": "Completed", + "artifacts": ["artifact-report-9"], + "evidence": ["evidence-test-4"], + "summary": "The candidate passed the required benchmark.", + "unresolvedQuestions": [], + "idempotencyKey": "result-attempt-7" +} +``` + +## Acceptance criteria + +- Agent communication survives runtime and coordinator restart. +- Every message is attributable and schema-valid. +- Duplicate delivery does not duplicate work or side effects. +- Authority cannot be delegated through prose. +- Parent context remains bounded as child count grows. +- Required joins depend on durable states and artifacts, not transcript inspection. +- Cancellation and revision notices supersede stale work. +- Sibling communication cannot create hidden dependency or authority paths. +- OSMO-hosted agents use the same durable protocol as control-plane agents. +- Human summaries preserve links to original messages and evidence. diff --git a/projects/agents/poc/README.md b/projects/agents/poc/README.md new file mode 100644 index 000000000..0e9f7b191 --- /dev/null +++ b/projects/agents/poc/README.md @@ -0,0 +1,8 @@ +# Agentic workflow POC components + +- [framework](framework): reusable OSMO agentic-workflow product surface. +- [skills/vda-two-video-poc](skills/vda-two-video-poc): opt-in VDA + demonstration skill and test fixture. + +The framework has no dependency on a domain skill. A domain is loaded only by +an explicit, commit-pinned task instruction. diff --git a/projects/agents/poc/framework/.gitignore b/projects/agents/poc/framework/.gitignore new file mode 100644 index 000000000..adf9410d0 --- /dev/null +++ b/projects/agents/poc/framework/.gitignore @@ -0,0 +1,5 @@ +.local/ +generated/ +__pycache__/ +*.pyc + diff --git a/projects/agents/poc/framework/Dockerfile b/projects/agents/poc/framework/Dockerfile new file mode 100644 index 000000000..ec43f628c --- /dev/null +++ b/projects/agents/poc/framework/Dockerfile @@ -0,0 +1,43 @@ +ARG UBUNTU_BASE_IMAGE +FROM ${UBUNTU_BASE_IMAGE} + +# Re-declare the parent argument inside the stage before verifying it. +ARG UBUNTU_BASE_IMAGE +ARG NODE_VERSION=24.15.0 +ARG NODE_ARCHIVE_SHA256=472655581fb851559730c48763e0c9d3bc25975c59d518003fc0849d3e4ba0f6 +ARG CODEX_VERSION=0.144.6 +ARG CODEX_NPM_INTEGRITY=sha512-wk+2CWiBNXiJLBoN2D08N9RceWkSBnlgk5g2K1a4CXrP/C0gdlHyRUG7RFzm9y41DCK/7tvCct233JVxyFmznw== + +SHELL ["/bin/bash", "-o", "pipefail", "-c"] + +RUN [[ "${UBUNTU_BASE_IMAGE}" =~ ^ubuntu:22\.04@sha256:[0-9a-f]{64}$ ]] \ + || { echo "UBUNTU_BASE_IMAGE must be a digest-pinned ubuntu:22.04 reference" >&2; exit 2; } \ + && apt-get update \ + && apt-get install -y --no-install-recommends ca-certificates curl git python3 tini xz-utils \ + && rm -rf /var/lib/apt/lists/* + +RUN curl --fail --location --silent --show-error "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.xz" --output /tmp/node.tar.xz \ + && echo "${NODE_ARCHIVE_SHA256} /tmp/node.tar.xz" | sha256sum --check --status \ + && tar --extract --xz --file /tmp/node.tar.xz --directory /opt \ + && ln -s "/opt/node-v${NODE_VERSION}-linux-x64/bin/node" /usr/local/bin/node \ + && ln -s "/opt/node-v${NODE_VERSION}-linux-x64/bin/npm" /usr/local/bin/npm \ + && rm /tmp/node.tar.xz \ + && test "$(npm view "@openai/codex@${CODEX_VERSION}" dist.integrity)" = "${CODEX_NPM_INTEGRITY}" \ + && npm install --global --ignore-scripts "@openai/codex@${CODEX_VERSION}" \ + && ln -s "/opt/node-v${NODE_VERSION}-linux-x64/bin/codex" /usr/local/bin/codex \ + && codex --version + +RUN useradd --create-home --shell /bin/bash agent \ + && mkdir -p /opt/agent-runtime /home/agent/.codex + +COPY runtime/codex-config.toml /home/agent/.codex/config.toml +COPY runtime/run-agent.sh /opt/agent-runtime/run-agent.sh + +RUN chmod 0555 /opt/agent-runtime/run-agent.sh \ + && chown -R agent:agent /opt/agent-runtime /home/agent + +USER agent +ENV HOME=/home/agent CODEX_HOME=/home/agent/.codex PATH=${PATH} PYTHONDONTWRITEBYTECODE=1 +WORKDIR /workspace +ENTRYPOINT ["/usr/bin/tini", "--"] +CMD ["/opt/agent-runtime/run-agent.sh", "--help"] diff --git a/projects/agents/poc/framework/README.md b/projects/agents/poc/framework/README.md new file mode 100644 index 000000000..ece4c9a86 --- /dev/null +++ b/projects/agents/poc/framework/README.md @@ -0,0 +1,104 @@ +# OSMO Agentic Workflow Framework + +This is the reusable product surface for a long-lived OSMO agent that plans, +delegates, reconciles, and safely retries bounded child workflows. It contains +the runtime contract, generic recursive-workflow skill, typed result/control +schemas, child-workflow template, and one generic entry capsule. + +It intentionally contains no domain workflow, worker image, input data, +model-cache, output contract, or domain-specific scheduling policy. A task +loads a public, commit-pinned domain skill only when its task-scoped +`AGENTS.md` explicitly requires one. + +## Contents + +- [agentic-workflow-spec.yaml](agentic-workflow-spec.yaml): the one + operator-submitted lead capsule. +- [skills/osmo-agentic-workflow](skills/osmo-agentic-workflow): generic child + creation, evidence, reconciliation, retry, and human-control rules. +- [runtime/run-agent.sh](runtime/run-agent.sh): the generic runtime entrypoint. + +## Local static checks + +```bash +cd /Users/fernandol/Workspace/osmo/external/projects/agents/poc/framework +( + set -euo pipefail + bash -n runtime/run-agent.sh + test "$(find skills -mindepth 1 -maxdepth 1 -type d | wc -l | tr -d ' ')" = 1 + test -d skills/osmo-agentic-workflow + python3 -m json.tool runtime-lock.json >/dev/null + python3 -m json.tool skills/osmo-agentic-workflow/assets/agent-result.schema.json >/dev/null + python3 -m json.tool skills/osmo-agentic-workflow/assets/human-response.schema.json >/dev/null + python3 -c 'import json; schema=json.load(open("skills/osmo-agentic-workflow/assets/agent-result.schema.json")); assert set(schema["required"]) == set(schema["properties"])' + python3 -c 'import json; schema=json.load(open("skills/osmo-agentic-workflow/assets/human-response.schema.json")); assert schema["properties"]["action"]["const"] == "continue"' + ruby -e ' + require "yaml" + skill = File.read(ARGV.shift) + match = skill.match(/\A---\n(.*?)\n---\n/m) or abort "invalid skill frontmatter" + metadata = YAML.safe_load(match[1], permitted_classes: [], aliases: false) + abort "invalid skill metadata" unless metadata.keys.sort == ["description", "name"] && metadata["name"] == "osmo-agentic-workflow" + ARGV.each { |path| YAML.load_file(path) } + ' skills/osmo-agentic-workflow/SKILL.md agentic-workflow-spec.yaml \ + skills/osmo-agentic-workflow/assets/child-workflow-template.yaml \ + skills/osmo-agentic-workflow/agents/openai.yaml + rg -q '^ agent_runtime_image: ".*@sha256:(REPLACE_WITH_64_HEX|[0-9a-f]{64})"$' agentic-workflow-spec.yaml + ! rg -n '^[[:space:]]*image:' skills/osmo-agentic-workflow/assets/child-workflow-template.yaml | rg -v '@sha256:(REPLACE_WITH_64_HEX|[0-9a-f]{64})"$' + ! rg -n -i '(^|[[:space:]])(auth|access_key|password):' agentic-workflow-spec.yaml skills/osmo-agentic-workflow/assets/child-workflow-template.yaml + rg -Fq 'STATIC_REPOSITORY_SUBDIR' runtime/run-agent.sh agentic-workflow-spec.yaml skills/osmo-agentic-workflow/assets/child-workflow-template.yaml + rg -Fq 'agentic_workflow_submit:' agentic-workflow-spec.yaml skills/osmo-agentic-workflow/assets/child-workflow-template.yaml + rg -Fq 'There is no numeric retry limit' skills/osmo-agentic-workflow/SKILL.md + rg -Fq 'human-response-.json' skills/osmo-agentic-workflow/SKILL.md + rg -Fq -- '--dangerously-bypass-approvals-and-sandbox' runtime/run-agent.sh + ! rg -Fq -- '--ask-for-approval' runtime/run-agent.sh + test "$(python3 -c 'import json; print(json.load(open("runtime-lock.json"))["agentRuntime"]["osmoUserSkill"]["ref"])')" = "$(sed -n "s/^readonly OSMO_SKILL_REF='\([0-9a-f]\{40\}\)'$/\1/p" runtime/run-agent.sh)" + rg -q '^ result_url: "swift://pdx\.s8k\.io/AUTH_team-osmo/dev/fernandol/agents_poc/agentic-workflows/' agentic-workflow-spec.yaml + rg -q '^ control_url: "swift://pdx\.s8k\.io/AUTH_team-osmo/dev/fernandol/agents_poc/agentic-workflows/' agentic-workflow-spec.yaml + rg -Fq '{{ goal_prompt | indent(8) }}' agentic-workflow-spec.yaml + printf '%s\n' 'framework static checks passed' +) +``` + +These checks are local only: they do not call OSMO, storage, inference, or +Docker. + +## Activate a domain goal + +Use a public repository and full commit SHA for both this framework and any +domain skill. The task-scoped goal names the domain-skill repository, commit, +and path, then directs the lead to read that skill before planning or +delegating. The framework does not implicitly discover or load domain skills. + +```bash +export STATIC_REPOSITORY_URL='https://github.com/NVIDIA/OSMO.git' +export STATIC_REPOSITORY_REF='' +export STATIC_REPOSITORY_SUBDIR='projects/agents/poc/framework' +export AGENT_RUNTIME_IMAGE='nvcr.io/nvstaging/osmo/agent-runtime@sha256:098afe976ab1dcc746a06835ad0b7e806eeeb7b410fddd84ad6132a3a8d9c20f' +export OSMO_SERVICE_URL='https://us-west-2-aws.osmo.nvidia.com' +export RUN_ID='agentic-' +export WORKFLOW_NAME="agentic-${RUN_ID}" +export RESULT_URL="swift://pdx.s8k.io/AUTH_team-osmo/dev/fernandol/agents_poc/agentic-workflows/run-${RUN_ID}/agent/lead/" +export CONTROL_URL="${RESULT_URL}control/" +export GOAL_PROMPT='' + +set_values=( + --set-string "workflow_name=$WORKFLOW_NAME" + --set-string "agent_runtime_image=$AGENT_RUNTIME_IMAGE" + --set-string "goal_prompt=$GOAL_PROMPT" + --set-string "static_repository_url=$STATIC_REPOSITORY_URL" + --set-string "static_repository_ref=$STATIC_REPOSITORY_REF" + --set-string "static_repository_subdir=$STATIC_REPOSITORY_SUBDIR" + --set-string "osmo_service_url=$OSMO_SERVICE_URL" + --set-string "run_id=$RUN_ID" + --set-string 'platform=' + --set-string "result_url=$RESULT_URL" + --set-string "control_url=$CONTROL_URL" +) + +osmo workflow submit agentic-workflow-spec.yaml --pool '' --dry-run "${set_values[@]}" +osmo workflow validate agentic-workflow-spec.yaml --pool '' "${set_values[@]}" +osmo workflow submit agentic-workflow-spec.yaml --pool '' --priority HIGH --format-type json "${set_values[@]}" +``` + +The operator submits only the lead. The lead and descendants own domain +planning, child construction, pool selection, reconciliation, and replacement. diff --git a/projects/agents/poc/framework/agentic-workflow-spec.yaml b/projects/agents/poc/framework/agentic-workflow-spec.yaml new file mode 100644 index 000000000..8db44b791 --- /dev/null +++ b/projects/agents/poc/framework/agentic-workflow-spec.yaml @@ -0,0 +1,88 @@ +version: 2 + +default-values: + workflow_name: agentic-workflow + agent_runtime_image: "nvcr.io/nvstaging/osmo/agent-runtime@sha256:REPLACE_WITH_64_HEX" + goal_prompt: "Describe the overarching goal for the lead agent." + static_repository_url: "https://github.com/REPLACE_WITH_OWNER/REPLACE_WITH_REPOSITORY.git" + static_repository_ref: "REPLACE_WITH_FULL_40_CHARACTER_COMMIT_SHA" + static_repository_subdir: "." + osmo_service_url: "https://us-west-2-aws.osmo.nvidia.com" + run_id: replace-with-dns-safe-run-id + platform: REPLACE_WITH_VISIBLE_PLATFORM + result_url: "swift://pdx.s8k.io/AUTH_team-osmo/dev/fernandol/agents_poc/agentic-workflows/replace-with-run-id/agent/lead/" + control_url: "swift://pdx.s8k.io/AUTH_team-osmo/dev/fernandol/agents_poc/agentic-workflows/replace-with-run-id/agent/lead/control/" + +workflow: + name: "{{workflow_name}}" + timeout: + queue_timeout: 30m + exec_timeout: 24h + resources: + lead: + cpu: 2 + memory: 4Gi + storage: 10Gi + platform: "{{platform}}" + tasks: + - name: lead + image: "{{agent_runtime_image}}" + resource: lead + credentials: + nvidia_inference: + INFERENCE_API_KEY: INFERENCE_API_KEY + agentic_workflow_submit: + OSMO_AGENTIC_WORKFLOW_TOKEN: OSMO_AGENTIC_WORKFLOW_TOKEN + environment: + RUN_ID: "{{run_id}}" + OSMO_SERVICE_URL: "{{osmo_service_url}}" + STATIC_REPOSITORY_URL: "{{static_repository_url}}" + STATIC_REPOSITORY_REF: "{{static_repository_ref}}" + STATIC_REPOSITORY_SUBDIR: "{{static_repository_subdir}}" + AGENT_RETRY_DELAY_SECONDS: "60" + AGENT_CONTROL_POLL_SECONDS: "60" + command: ["/opt/agent-runtime/run-agent.sh"] + args: + - "--result-root" + - "{{output}}" + - "--control-url" + - "{{control_url}}" + files: + - path: /run/agent/AGENTS.md + contents: | + # Lead agent + + Own the overarching user goal below for the lifetime of this workflow. + Translate it into a small, explicit plan; delegate each meaningful + bounded subgoal; and reconcile every delegated result. Do not perform + a delegated subgoal's domain work directly or predefine its worker + graph. + + Before delegating, reconcile workflow and durable artifact evidence for + this Run ID. Reuse every existing child whose typed result satisfies its + contract. Submit the same logical child only when none exists, or when + a prior non-successful child is terminal and a replacement is warranted; + a previous lead attempt being terminal is not itself a reason to repeat + successful descendant work. + + Do not mutate OSMO pools, profiles, quotas, credentials, or service + configuration. Request human direction only for ambiguity that cannot + be resolved safely from this task's instructions, evidence, and OSMO + state. + + Run ID: {{run_id}} + + ## User goal + + {{ goal_prompt | indent(8) }} + checkpoint: + - path: "{{output}}/*" + url: "{{result_url}}" + frequency: 60s + regex: '^agent-result\.json$' + - path: /tmp/agent-control/* + url: "{{control_url}}" + frequency: 60s + regex: '^human-request-[0-9a-f]{64}\.json$' + outputs: + - url: "{{result_url}}" diff --git a/projects/agents/poc/framework/runtime-lock.json b/projects/agents/poc/framework/runtime-lock.json new file mode 100644 index 000000000..948f37352 --- /dev/null +++ b/projects/agents/poc/framework/runtime-lock.json @@ -0,0 +1,44 @@ +{ + "schemaVersion": "v1", + "agentRuntime": { + "parent": "ubuntu:22.04@sha256:0d779ea97881505f5ef0039336ee85edba27519bdba968c284c86ee066a973c8", + "publishReference": "nvcr.io/nvstaging/osmo/agent-runtime:poc-human-control-v1-d876de19c", + "image": "nvcr.io/nvstaging/osmo/agent-runtime@sha256:098afe976ab1dcc746a06835ad0b7e806eeeb7b410fddd84ad6132a3a8d9c20f", + "platform": "linux/amd64", + "registryCredential": "ngc_cred", + "osmoCli": { + "source": "existing OSMO task runtime", + "requiredCommands": ["pool list", "resource list", "workflow submit", "workflow validate", "workflow query", "workflow logs", "workflow events", "workflow cancel", "data check", "data download"] + }, + "agenticWorkflowSubmit": { + "name": "agentic_workflow_submit", + "type": "GENERIC", + "runtimeKey": "OSMO_AGENTIC_WORKFLOW_TOKEN", + "serviceUrl": "https://us-west-2-aws.osmo.nvidia.com" + }, + "osmoUserSkill": { + "repository": "https://github.com/NVIDIA/OSMO.git", + "ref": "3603b853f62dd38dfe1dc0a76cf68dfa3f07461a", + "path": "skills/osmo-user" + }, + "node": { + "version": "24.15.0", + "archive": "node-v24.15.0-linux-x64.tar.xz", + "archiveSha256": "472655581fb851559730c48763e0c9d3bc25975c59d518003fc0849d3e4ba0f6" + }, + "pythonVersion": "3.10" + }, + "codex": { + "package": "@openai/codex", + "version": "0.144.6", + "npmIntegrity": "sha512-wk+2CWiBNXiJLBoN2D08N9RceWkSBnlgk5g2K1a4CXrP/C0gdlHyRUG7RFzm9y41DCK/7tvCct233JVxyFmznw==", + "provider": "nvidia_inference", + "model": "openai/openai/gpt-5.6-terra", + "reasoningEffort": "xhigh" + }, + "credentials": { + "registry": {"name": "ngc_cred", "type": "REGISTRY", "registry": "nvcr.io"}, + "inference": {"name": "nvidia_inference", "type": "GENERIC", "runtimeKey": "INFERENCE_API_KEY"}, + "workflowSubmit": {"name": "agentic_workflow_submit", "type": "GENERIC", "runtimeKey": "OSMO_AGENTIC_WORKFLOW_TOKEN"} + } +} diff --git a/projects/agents/poc/framework/runtime/codex-config.toml b/projects/agents/poc/framework/runtime/codex-config.toml new file mode 100644 index 000000000..1dd1044c6 --- /dev/null +++ b/projects/agents/poc/framework/runtime/codex-config.toml @@ -0,0 +1,13 @@ +model = "openai/openai/gpt-5.6-terra" +model_provider = "nvidia_inference" +model_reasoning_effort = "xhigh" +approval_policy = "never" +sandbox_mode = "danger-full-access" +project_root_markers = [] + +[model_providers.nvidia_inference] +name = "Nvidia Inference (Codex)" +base_url = "https://inference-api.nvidia.com/v1/" +env_key = "INFERENCE_API_KEY" +wire_api = "responses" +requires_openai_auth = false diff --git a/projects/agents/poc/framework/runtime/run-agent.sh b/projects/agents/poc/framework/runtime/run-agent.sh new file mode 100755 index 000000000..c8f7e4184 --- /dev/null +++ b/projects/agents/poc/framework/runtime/run-agent.sh @@ -0,0 +1,371 @@ +#!/usr/bin/env bash +# Start a generic agent with its pinned static capabilities. +set -euo pipefail + +readonly OSMO_SKILL_REPOSITORY='https://github.com/NVIDIA/OSMO.git' +readonly OSMO_SKILL_REF='3603b853f62dd38dfe1dc0a76cf68dfa3f07461a' +readonly AGENTS_FILE='/run/agent/AGENTS.md' +readonly DEFAULT_OSMO_SERVICE_URL='https://us-west-2-aws.osmo.nvidia.com' +readonly STORAGE_URL_PATTERN='^(swift|s3|gs|tos|azure)://[^/:[:space:]]+(/[^[:space:]]+)*/*$' + +result_root="" +control_url="" +while [[ $# -gt 0 ]]; do + case "$1" in + --result-root) result_root="$2"; shift 2 ;; + --control-url) control_url="$2"; shift 2 ;; + -h|--help) + echo "Usage: run-agent.sh --result-root --control-url " + exit 0 + ;; + *) echo "unknown argument: $1" >&2; exit 2 ;; + esac +done + +[[ -n "${result_root}" ]] || { echo "--result-root is required" >&2; exit 2; } +[[ -n "${control_url}" ]] || { echo "--control-url is required" >&2; exit 2; } +[[ -r "${AGENTS_FILE}" ]] || { echo "${AGENTS_FILE} is required and must be readable" >&2; exit 2; } +[[ -n "${INFERENCE_API_KEY:-}" ]] || { echo "INFERENCE_API_KEY is required at runtime" >&2; exit 2; } +[[ -n "${OSMO_AGENTIC_WORKFLOW_TOKEN:-}" ]] || { + echo "OSMO_AGENTIC_WORKFLOW_TOKEN is required at runtime" >&2 + exit 2 +} +command -v osmo >/dev/null || { echo "OSMO CLI is not available in this task runtime" >&2; exit 2; } + +[[ "${control_url}" =~ ${STORAGE_URL_PATTERN} ]] || { + echo "--control-url must be an OSMO storage URL without credentials" >&2 + exit 2 +} +control_url="${control_url%/}/" + +osmo_service_url="${OSMO_SERVICE_URL:-${DEFAULT_OSMO_SERVICE_URL}}" +[[ "${osmo_service_url}" =~ ^https://[A-Za-z0-9.-]+$ ]] || { + echo "OSMO_SERVICE_URL must be an https service root without a path" >&2 + exit 2 +} + +# Pass the one-time credential through an inherited file descriptor rather than +# an argument or a file, then remove it from the environment before Codex runs. +osmo login "${osmo_service_url}" --method token --token-file /dev/fd/3 \ + 3<<<"${OSMO_AGENTIC_WORKFLOW_TOKEN}" >/dev/null +unset OSMO_AGENTIC_WORKFLOW_TOKEN + +checkout_pinned() { + local repository_url="$1" repository_ref="$2" destination="$3" + git clone --quiet --no-checkout "${repository_url}" "${destination}" + git -C "${destination}" checkout --quiet --detach "${repository_ref}" + [[ "$(git -C "${destination}" rev-parse HEAD)" == "${repository_ref}" ]] || { + echo "checked out source does not match its pinned commit" >&2 + exit 2 + } +} + +[[ "${STATIC_REPOSITORY_URL:-}" =~ ^https://github\.com/[^/]+/[^/]+(\.git)?$ ]] || { + echo "STATIC_REPOSITORY_URL must be a public https://github.com//[.git] URL" >&2 + exit 2 +} +[[ "${STATIC_REPOSITORY_REF:-}" =~ ^[0-9a-f]{40}$ ]] || { + echo "STATIC_REPOSITORY_REF must be a full immutable Git commit SHA" >&2 + exit 2 +} +static_repository_subdir="${STATIC_REPOSITORY_SUBDIR:-.}" +if [[ "${static_repository_subdir}" != "." ]] && \ + { ! [[ "${static_repository_subdir}" =~ ^[A-Za-z0-9][A-Za-z0-9._-]*(/[A-Za-z0-9][A-Za-z0-9._-]*)*$ ]] || \ + [[ "/${static_repository_subdir}/" == *"/./"* || "/${static_repository_subdir}/" == *"/../"* ]]; }; then + echo "STATIC_REPOSITORY_SUBDIR must be . or a relative, traversal-free path" >&2 + exit 2 +fi + +kit_root="$(mktemp -d /tmp/agent-kit.XXXXXX)" +osmo_root="$(mktemp -d /tmp/osmo-user.XXXXXX)" +checkout_pinned "${STATIC_REPOSITORY_URL}" "${STATIC_REPOSITORY_REF}" "${kit_root}" +checkout_pinned "${OSMO_SKILL_REPOSITORY}" "${OSMO_SKILL_REF}" "${osmo_root}" +kit_workdir="${kit_root}/${static_repository_subdir}" +agentic_skill_root="${kit_workdir}/skills/osmo-agentic-workflow" +agentic_skill_file="${agentic_skill_root}/SKILL.md" +agentic_result_schema="${agentic_skill_root}/assets/agent-result.schema.json" +human_response_schema="${agentic_skill_root}/assets/human-response.schema.json" +child_template="${agentic_skill_root}/assets/child-workflow-template.yaml" +osmo_skill_file="${osmo_root}/skills/osmo-user/SKILL.md" +[[ -d "${kit_workdir}" && -f "${agentic_skill_file}" && -f "${agentic_result_schema}" && -f "${human_response_schema}" && -f "${child_template}" && -f "${osmo_skill_file}" ]] || { + echo "cloned sources do not provide the required agentic-workflow skill at STATIC_REPOSITORY_SUBDIR=${static_repository_subdir}" >&2 + exit 2 +} + +python3 - "${human_response_schema}" <<'PY' +import json +import sys +from pathlib import Path + +schema = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8")) +expected = {"schemaVersion", "requestId", "action", "instruction"} +if schema.get("required") != ["schemaVersion", "requestId", "action", "instruction"]: + raise SystemExit("human response schema has an unexpected required-field contract") +if set(schema.get("properties", {})) != expected: + raise SystemExit("human response schema has an unexpected property contract") +if schema["properties"]["schemaVersion"].get("const") != "v1": + raise SystemExit("human response schema must pin schemaVersion v1") +if schema["properties"]["action"].get("const") != "continue": + raise SystemExit("human response schema must pin action continue") +PY + +mkdir -p "${result_root}" +prompt_file="$(mktemp /tmp/agent-prompt.XXXXXX)" +iteration_result="$(mktemp /tmp/agent-result.XXXXXX)" +human_response_file="$(mktemp /tmp/human-response.XXXXXX)" +control_request_dir="/tmp/agent-control" +result_file="${result_root}/agent-result.json" +mkdir -p "${control_request_dir}" +chmod 0755 "${control_request_dir}" +trap 'rm -f "${prompt_file}" "${iteration_result}" "${human_response_file}"' EXIT + +positive_integer() { + [[ "$1" =~ ^[1-9][0-9]*$ ]] +} + +retry_delay_seconds="${AGENT_RETRY_DELAY_SECONDS:-60}" +control_poll_seconds="${AGENT_CONTROL_POLL_SECONDS:-60}" +positive_integer "${retry_delay_seconds}" || { + echo "AGENT_RETRY_DELAY_SECONDS must be a positive integer" >&2 + exit 2 +} +positive_integer "${control_poll_seconds}" || { + echo "AGENT_CONTROL_POLL_SECONDS must be a positive integer" >&2 + exit 2 +} + +validate_agent_result() { + python3 - "$1" <<'PY' +import json +import sys +from pathlib import Path + +result_path = Path(sys.argv[1]) +try: + result = json.loads(result_path.read_text(encoding="utf-8")) +except (OSError, json.JSONDecodeError) as error: + raise SystemExit(f"invalid agent result: {error}") + +required = {"outcome", "summary", "evidence", "nextAction"} +if not isinstance(result, dict) or set(result) != required: + raise SystemExit("agent result must contain exactly outcome, summary, evidence, and nextAction") +if result["outcome"] not in { + "Completed", + "Retrying", + "HumanInterventionRequired", + "TerminalFailure", +}: + raise SystemExit("agent result contains an unknown outcome") +if not isinstance(result["summary"], str) or not result["summary"].strip(): + raise SystemExit("agent result summary must be a non-empty string") +if not isinstance(result["evidence"], list) or not all( + isinstance(item, str) for item in result["evidence"] +): + raise SystemExit("agent result evidence must be an array of strings") +if result["nextAction"] is not None and not isinstance(result["nextAction"], str): + raise SystemExit("agent result nextAction must be a string or null") +print(result["outcome"]) +PY +} + +write_prompt() { + { + printf '## Reusable OSMO agentic-workflow skill\n\n' + cat "${agentic_skill_file}" + printf '\n\n## OSMO operating skill\n\n' + cat "${osmo_skill_file}" + printf '\n\n## Task-scoped AGENTS instructions\n\n' + cat "${AGENTS_FILE}" + printf '\nThe full OSMO skill source, including its references, is at %s/skills/osmo-user. Before any OSMO operation, read the relevant reference there and use the existing OSMO CLI directly. The static-kit root is %s. The generic child workflow template is %s. Copy it to a new child YAML and edit the copy; preserve STATIC_REPOSITORY_URL, STATIC_REPOSITORY_REF, and STATIC_REPOSITORY_SUBDIR from this task. Its embedded task-scoped AGENTS.md is the complete handoff. Record child workflow IDs and output URLs in durable evidence before monitoring or retrying. Clone additional public, commit-pinned domain repositories only when the task-scoped AGENTS.md requires them. Do not place secret values in output. For a genuine unresolved ambiguity, return HumanInterventionRequired with the exact question and safe choices in nextAction. The runtime will publish that request and wait for a matched human response; do not treat that outcome as completion.\n' "${osmo_root}" "${kit_workdir}" "${child_template}" + if [[ -f "${result_file}" ]]; then + printf '\n## Continuation\n\n' + printf 'This is a continuation of the same bounded task, not a new goal. The previous typed result is below. Read it and its durable evidence before acting. Reconcile already-submitted child workflows before retrying or submitting a replacement. A `Retrying` result is not completion: perform the stated next action, then return a new typed result. Do not repeat a non-terminal child submission.\n\n' + cat "${result_file}" + printf '\n' + fi + if [[ -s "${human_response_file}" ]]; then + printf '\n## Human response\n\n' + printf 'The runtime validated this response for the prior human-intervention request. Apply it to the same bounded task, reconcile current OSMO state first, and continue safely.\n\n' + cat "${human_response_file}" + printf '\n' + fi + } > "${prompt_file}" +} + +create_human_request() { + local request_id + request_id="$(python3 - "${iteration_result}" "${control_url}" "${control_request_dir}" <<'PY' +import hashlib +import json +import os +import sys +import tempfile +from pathlib import Path + +result_path = Path(sys.argv[1]) +control_url = sys.argv[2].rstrip("/") +request_dir = Path(sys.argv[3]) +result = json.loads(result_path.read_text(encoding="utf-8")) + +if result.get("outcome") != "HumanInterventionRequired": + raise SystemExit("human request requires HumanInterventionRequired") +question = result.get("nextAction") +if not isinstance(question, str) or not question.strip(): + raise SystemExit("HumanInterventionRequired requires a non-empty nextAction") + +fingerprint = { + "summary": result["summary"], + "evidence": result["evidence"], + "question": question, +} +request_id = hashlib.sha256( + json.dumps(fingerprint, sort_keys=True, separators=(",", ":")).encode("utf-8") +).hexdigest() +request = { + "schemaVersion": "v1", + "requestId": request_id, + "summary": result["summary"], + "evidence": result["evidence"], + "question": question, + "responseUrl": f"{control_url}/human-response-{request_id}.json", +} +request_dir.mkdir(parents=True, exist_ok=True) +target = request_dir / f"human-request-{request_id}.json" +descriptor, temporary_name = tempfile.mkstemp(prefix=".human-request-", dir=request_dir) +try: + with os.fdopen(descriptor, "w", encoding="utf-8") as temporary: + json.dump(request, temporary, sort_keys=True, separators=(",", ":")) + temporary.write("\n") + os.chmod(temporary_name, 0o644) + os.replace(temporary_name, target) +except BaseException: + try: + os.unlink(temporary_name) + except FileNotFoundError: + pass + raise + +print(request_id) +PY +)" || return 1 + printf '%s\n' "${request_id}" +} + +validate_human_response() { + python3 - "$1" "$2" <<'PY' +import json +import sys +from pathlib import Path + +response_path = Path(sys.argv[1]) +request_id = sys.argv[2] +try: + response = json.loads(response_path.read_text(encoding="utf-8")) +except (OSError, json.JSONDecodeError) as error: + raise SystemExit(f"invalid human response: {error}") + +required = {"schemaVersion", "requestId", "action", "instruction"} +if not isinstance(response, dict) or set(response) != required: + raise SystemExit("human response must contain exactly schemaVersion, requestId, action, and instruction") +if response["schemaVersion"] != "v1": + raise SystemExit("human response has an unsupported schemaVersion") +if response["requestId"] != request_id: + raise SystemExit("human response requestId does not match the active request") +if response["action"] != "continue": + raise SystemExit("human response action must be continue") +if not isinstance(response["instruction"], str) or not response["instruction"].strip(): + raise SystemExit("human response instruction must be a non-empty string") +PY +} + +wait_for_human_response() { + local request_id="$1" + local response_url="${control_url}human-response-${request_id}.json" + local response_dir response_path poll_count=0 + + echo "Agent requires human intervention; request ID: ${request_id}" >&2 + echo "Human request will checkpoint to: ${control_url}human-request-${request_id}.json" >&2 + echo "Awaiting matched human response at: ${response_url}" >&2 + osmo data check "${control_url}" --access-type READ >/dev/null || { + echo "Human control inbox is not readable: ${control_url}" >&2 + return 1 + } + + while :; do + response_dir="$(mktemp -d /tmp/human-response-download.XXXXXX)" + if osmo data download "${response_url}" "${response_dir}" >"${response_dir}/download.log" 2>&1; then + response_path="$(find "${response_dir}" -type f -name "human-response-${request_id}.json" -print -quit)" + if [[ -n "${response_path}" ]] && validate_human_response "${response_path}" "${request_id}"; then + install -m 0600 "${response_path}" "${human_response_file}" + rm -rf "${response_dir}" + echo "Received valid human response for request ID: ${request_id}" >&2 + return 0 + fi + echo "Ignoring an invalid human response for request ID: ${request_id}" >&2 + fi + rm -rf "${response_dir}" + poll_count=$((poll_count + 1)) + if (( poll_count % 5 == 0 )); then + echo "Still awaiting human response for request ID: ${request_id}" >&2 + fi + sleep "${control_poll_seconds}" + done +} + +iteration=1 +while :; do + write_prompt + : > "${iteration_result}" + echo "Starting Codex agent iteration ${iteration}" >&2 + if ! codex exec \ + --strict-config \ + --dangerously-bypass-approvals-and-sandbox \ + --skip-git-repo-check \ + --ephemeral \ + --json \ + --output-schema "${agentic_result_schema}" \ + --output-last-message "${iteration_result}" \ + -C "${kit_workdir}" \ + - < "${prompt_file}"; then + echo "Codex agent iteration ${iteration} failed before producing a terminal result" >&2 + exit 1 + fi + + # A human response is a one-turn continuation input. Later turns must rely + # on the newly returned typed result and durable evidence instead. + : > "${human_response_file}" + + outcome="$(validate_agent_result "${iteration_result}")" || { + echo "Codex agent iteration ${iteration} produced an invalid typed result" >&2 + exit 1 + } + install -m 0644 "${iteration_result}" "${result_file}" + + case "${outcome}" in + Completed) + echo "Agent completed after iteration ${iteration}" >&2 + exit 0 + ;; + Retrying) + echo "Agent requested continuation after iteration ${iteration}; waiting ${retry_delay_seconds}s" >&2 + sleep "${retry_delay_seconds}" + iteration=$((iteration + 1)) + ;; + HumanInterventionRequired) + request_id="$(create_human_request)" || { + echo "Unable to publish a valid human-intervention request" >&2 + exit 1 + } + wait_for_human_response "${request_id}" || exit 1 + iteration=$((iteration + 1)) + ;; + TerminalFailure) + echo "Agent reached TerminalFailure after iteration ${iteration}" >&2 + exit 1 + ;; + *) + echo "Agent produced an unsupported outcome after iteration ${iteration}" >&2 + exit 1 + ;; + esac +done diff --git a/projects/agents/poc/framework/skills/osmo-agentic-workflow/SKILL.md b/projects/agents/poc/framework/skills/osmo-agentic-workflow/SKILL.md new file mode 100644 index 000000000..84abd678a --- /dev/null +++ b/projects/agents/poc/framework/skills/osmo-agentic-workflow/SKILL.md @@ -0,0 +1,127 @@ +--- +name: osmo-agentic-workflow +description: Create, submit, monitor, and recursively delegate OSMO child workflows for a bounded agent subgoal. Use when an agent must turn part of its goal into a new OSMO workflow, embed a child AGENTS.md, monitor a child, or safely retry a terminal child workflow. +--- + +# OSMO Agentic Workflow + +Use this skill with `osmo-user`. `osmo-user` owns correct OSMO CLI usage; +this skill owns the recursive-agent handoff. + +## Bounded child authority + +When the task-scoped `AGENTS.md` supplies a bounded child subgoal, own exactly that +subgoal. Plan and execute it, including further bounded delegation when it is +needed. Do not change the parent goal or execute a different subgoal. + +Select a domain skill, script, or deterministic worker only from a public +repository pinned to a full commit SHA, and record that source in durable +evidence. Preserve the child template's runtime-image, static-repository URL, +commit SHA, and `STATIC_REPOSITORY_SUBDIR` (use `.` when the kit is at the +repository root) unless the parent task instructions explicitly supply +replacements. + +Preserve the `agentic_workflow_submit` credential mapping. Replace the child +template's `REPLACE_WITH_OSMO_SERVICE_HOST` with the parent task's +`OSMO_SERVICE_URL` host. Together they give the child its runtime-only ability +to authenticate to OSMO and recursively delegate; never copy a token value +into YAML, instructions, evidence, or artifacts. + +Give every child its own control URL beneath that child's result URL. The +control URL is a non-secret object-storage location for a checkpointed human +request and matched response; it is not inherited from the parent and is not a +credential. + +Carry every active parent execution policy into the child's `AGENTS.md`, +including its priority, pool-selection constraints, and any narrowly granted +replacement authority. Do not invent cancellation authority in a generic child +handoff. + +Do not treat the parent workflow's pool as the child's default or as evidence +that it is the best fit. When the inherited policy permits selection across the +user's accessible compute, the child must make its own fresh selection. + +## Pass verified evidence by reference + +Pass a parent artifact to a child only as its immutable URL and SHA-256. Put +those two values in the child `AGENTS.md`; do not copy derived fields from the +artifact into prose or reconstruct a URL from a prefix. The child must download +the referenced bytes, verify the SHA-256, parse the verified artifact locally, +and use the fields it contains exactly as written. + +For example, a parent result manifest passes only its URL and SHA-256. The +child verifies that document, then reads its exact artifact locations and +contract fields from the verified bytes. This rule applies to every artifact +type. + +## Create one child + +1. Bound the child to one clear subgoal, acceptance criteria, and relevant + parent evidence. Escalate ambiguity that cannot be resolved safely. +2. Copy `assets/child-workflow-template.yaml` to a new child YAML. +3. Replace every `REPLACE_*` value and write the bounded subgoal into + `/run/agent/AGENTS.md` in that YAML. Include immutable parent-evidence URLs + and SHA-256 values only. Do not put secret values or copied artifact fields + in it. +4. When the parent permits pool selection, read `osmo-user` resource guidance, + inspect all pools and resource profiles accessible to the user, and select + the best-fit compatible pool/platform for this capsule. Base the selection + on the declared resource profile, image-platform compatibility, and current + observed scheduling evidence; record the eligible choices, selection, and + reason in durable evidence before submission. +5. Read the relevant `osmo-user` reference, then use the existing OSMO CLI to + preview, validate, and submit the child YAML. Select `--priority` exactly + from the inherited parent execution policy and the child's declared resource + profile; do not infer a different priority. +6. Persist the returned workflow ID, output URL, pool, platform, and priority + in the parent result's evidence before monitoring it. + +## Monitor, recurse, and retry + +Use `osmo-user` and the existing CLI to query child state, inspect logs/events +when needed, and collect its output. A child agent may repeat this same +process for a further bounded subgoal. + +Before retrying, query the previous child and reconcile its typed result and +referenced evidence. A terminal OSMO workflow status alone is not a successful +subgoal. Create a new immutable child YAML only after the previous child is +terminal. There is no numeric retry limit. + +When the parent explicitly grants capacity-migration authority, a child that +has not started work and is demonstrably blocked may be canceled without +`--force`, reconciled to a terminal state, and replaced on another verified +eligible pool. Never cancel a running child merely to chase capacity and never +submit a parallel replacement for a non-terminal child. Without that explicit +authority, leave the child intact and return `Retrying` while it remains a +known non-terminal condition. + +Return `Retrying` for known non-terminal conditions, including an existing +child that is pending, temporarily out of capacity, or still producing its +declared result. State the exact reconciliation or recovery action in +`nextAction`. The runtime applies a controlled delay before starting another +Codex turn with the prior typed result, so read that result and its evidence +instead of restating the plan or treating prior children as new. + +Return `Completed` only after reconciling every child needed for the assigned +acceptance criteria. Return `HumanInterventionRequired` only for an ambiguity +that cannot be resolved safely from the task contract, evidence, and OSMO +state. Its `nextAction` must be a concrete question and the safe choices the +human must decide. The runtime writes a request with a content-derived request +ID to the task's checkpointed control URL, then waits for the matching +`human-response-.json`; it does not complete the OSMO task. A +valid response has exactly `schemaVersion: "v1"`, that `requestId`, +`action: "continue"`, and a non-empty `instruction`. The next Codex turn gets +that instruction and continues the same bounded task. + +## Boundaries + +Do not create hidden sidecars, controller wrappers, state ledgers, +or workflow contracts. The child YAML is the complete immutable +handoff. Do not mutate OSMO pools, quotas, credentials, server configuration, +or Kubernetes resources. + +## Assets + +- `assets/child-workflow-template.yaml`: copy and complete for each child. +- `assets/agent-result.schema.json`: final response shape for agents. +- `assets/human-response.schema.json`: required operator response shape. diff --git a/projects/agents/poc/framework/skills/osmo-agentic-workflow/agents/openai.yaml b/projects/agents/poc/framework/skills/osmo-agentic-workflow/agents/openai.yaml new file mode 100644 index 000000000..9dd83c6c2 --- /dev/null +++ b/projects/agents/poc/framework/skills/osmo-agentic-workflow/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "OSMO Agentic Workflow" + short_description: "Delegate recursive OSMO agent workflows" + default_prompt: "Use $osmo-agentic-workflow to create and manage a child OSMO workflow for this bounded subgoal." diff --git a/projects/agents/poc/framework/skills/osmo-agentic-workflow/assets/agent-result.schema.json b/projects/agents/poc/framework/skills/osmo-agentic-workflow/assets/agent-result.schema.json new file mode 100644 index 000000000..82a3fd26f --- /dev/null +++ b/projects/agents/poc/framework/skills/osmo-agentic-workflow/assets/agent-result.schema.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "AgentResult/v1", + "type": "object", + "required": ["outcome", "summary", "evidence", "nextAction"], + "properties": { + "outcome": {"enum": ["Completed", "Retrying", "HumanInterventionRequired", "TerminalFailure"]}, + "summary": {"type": "string", "minLength": 1}, + "evidence": {"type": "array", "items": {"type": "string"}}, + "nextAction": {"type": ["string", "null"]} + }, + "additionalProperties": false +} diff --git a/projects/agents/poc/framework/skills/osmo-agentic-workflow/assets/child-workflow-template.yaml b/projects/agents/poc/framework/skills/osmo-agentic-workflow/assets/child-workflow-template.yaml new file mode 100644 index 000000000..06596dc58 --- /dev/null +++ b/projects/agents/poc/framework/skills/osmo-agentic-workflow/assets/child-workflow-template.yaml @@ -0,0 +1,58 @@ +version: 2 + +# Copy this shape into a new child YAML and replace every REPLACE_* value. The +# child YAML, including its task-scoped AGENTS.md below, is the complete handoff. +workflow: + name: replace-with-dns-safe-child-name + timeout: + queue_timeout: 30m + exec_timeout: 24h + resources: + agent: + cpu: 2 + memory: 4Gi + storage: 10Gi + platform: REPLACE_WITH_VISIBLE_PLATFORM + tasks: + - name: agent + image: "nvcr.io/nvstaging/osmo/agent-runtime@sha256:REPLACE_WITH_64_HEX" + resource: agent + credentials: + nvidia_inference: + INFERENCE_API_KEY: INFERENCE_API_KEY + agentic_workflow_submit: + OSMO_AGENTIC_WORKFLOW_TOKEN: OSMO_AGENTIC_WORKFLOW_TOKEN + environment: + OSMO_SERVICE_URL: "https://REPLACE_WITH_OSMO_SERVICE_HOST" + STATIC_REPOSITORY_URL: "https://github.com/REPLACE_WITH_OWNER/REPLACE_WITH_REPOSITORY.git" + STATIC_REPOSITORY_REF: "REPLACE_WITH_FULL_40_CHARACTER_COMMIT_SHA" + STATIC_REPOSITORY_SUBDIR: "." + AGENT_RETRY_DELAY_SECONDS: "60" + AGENT_CONTROL_POLL_SECONDS: "60" + command: ["/opt/agent-runtime/run-agent.sh"] + args: + - "--result-root" + - "{{output}}" + - "--control-url" + - "swift://REPLACE_WITH_SWIFT_HOST/REPLACE_WITH_SWIFT_NAMESPACE/REPLACE_WITH_CONTAINER/agent-results/replace-with-child-name/control/" + files: + - path: /run/agent/AGENTS.md + contents: | + # Child agent + + Replace this with the bounded child subgoal, acceptance criteria, and + relevant parent evidence. Pass each parent artifact only as its exact + immutable URL and SHA-256. Download and verify it before using its + fields; do not reconstruct or copy derived values from prose. Do not + include secret values. + checkpoint: + - path: "{{output}}/*" + url: "swift://REPLACE_WITH_SWIFT_HOST/REPLACE_WITH_SWIFT_NAMESPACE/REPLACE_WITH_CONTAINER/agent-results/replace-with-child-name/" + frequency: 60s + regex: '^agent-result\.json$' + - path: /tmp/agent-control/* + url: "swift://REPLACE_WITH_SWIFT_HOST/REPLACE_WITH_SWIFT_NAMESPACE/REPLACE_WITH_CONTAINER/agent-results/replace-with-child-name/control/" + frequency: 60s + regex: '^human-request-[0-9a-f]{64}\.json$' + outputs: + - url: "swift://REPLACE_WITH_SWIFT_HOST/REPLACE_WITH_SWIFT_NAMESPACE/REPLACE_WITH_CONTAINER/agent-results/replace-with-child-name/" diff --git a/projects/agents/poc/framework/skills/osmo-agentic-workflow/assets/human-response.schema.json b/projects/agents/poc/framework/skills/osmo-agentic-workflow/assets/human-response.schema.json new file mode 100644 index 000000000..17c3ec9b8 --- /dev/null +++ b/projects/agents/poc/framework/skills/osmo-agentic-workflow/assets/human-response.schema.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "HumanResponse/v1", + "type": "object", + "required": ["schemaVersion", "requestId", "action", "instruction"], + "properties": { + "schemaVersion": {"const": "v1"}, + "requestId": {"type": "string", "pattern": "^[0-9a-f]{64}$"}, + "action": {"const": "continue"}, + "instruction": {"type": "string", "minLength": 1} + }, + "additionalProperties": false +} diff --git a/projects/agents/poc/skills/vda-two-video-poc/README.md b/projects/agents/poc/skills/vda-two-video-poc/README.md new file mode 100644 index 000000000..9993cf1d1 --- /dev/null +++ b/projects/agents/poc/skills/vda-two-video-poc/README.md @@ -0,0 +1,152 @@ + + +# VDA two-video POC domain skill + +Status: opt-in demonstration and framework test + +This directory is intentionally separate from +[`../../framework/README.md`](../../framework/README.md). The framework ships only generic agentic +workflow mechanics; this skill owns the VDA topology, PAIDF/image details, +model-cache materializer, fixed video inputs, and output contract. A framework +task loads this domain only when its task-scoped goal explicitly names this +skill at a pinned repository commit. + +## Load from the framework + +Submit the generic [framework entry capsule](../../framework/agentic-workflow-spec.yaml) +with `STATIC_REPOSITORY_SUBDIR=projects/agents/poc/framework`. The task-scoped +goal must name the same public repository, full commit SHA, and this skill path +(`projects/agents/poc/skills/vda-two-video-poc`), then require the lead to +clone that source and read [SKILL.md](SKILL.md) and its referenced contracts +before it plans or delegates. Do not copy this skill's worker code or contract +text into the framework. + +## Local static checks + +```bash +cd /Users/fernandol/Workspace/osmo/external/projects/agents/poc/skills/vda-two-video-poc +( + set -euo pipefail + bash -n assets/model-artifact-materializer/materialize-model-artifacts.sh + python3 -m json.tool assets/model-artifact-materializer/model-artifact-sources-v1.json >/dev/null + python3 -c 'from pathlib import Path; path=Path("assets/model-artifact-materializer/verify-vda-cache.py"); compile(path.read_text(encoding="utf-8"), str(path), "exec")' + python3 assets/model-artifact-materializer/verify-vda-cache.py --help >/dev/null + ruby -e ' + require "yaml" + skill = File.read(ARGV.fetch(0)) + match = skill.match(/\A---\n(.*?)\n---\n/m) or abort "invalid skill frontmatter" + metadata = YAML.safe_load(match[1], permitted_classes: [], aliases: false) + abort "invalid skill metadata" unless metadata.keys.sort == ["description", "name"] && metadata["name"] == "vda-two-video-poc" + ' SKILL.md + for reference in references/*.md; do test -s "$reference"; done + rg -Fq 'assets/model-artifact-materializer' SKILL.md + rg -Fq 'https://inference-api.nvidia.com/v1' SKILL.md references/locked-topology.md + printf '%s\n' 'VDA skill static checks passed' +) +``` + +## Purpose + +Prove the smallest useful agentic-goals loop without a product UI or changes to +OSMO services. The goal runs entirely in the user's persistent +`fernandol-dev.osmo.nvidia.com` environment through one custom agent image, +pinned upstream PAIDF images, custom workflow YAML, custom task scripts, and +the existing OSMO CLI/API. + +The POC must answer four questions: + +1. Can a long-lived OSMO-hosted lead translate one VDA goal into a bounded, + inspectable plan? +2. Can it delegate a bounded environment pipeline and one bounded video + pipeline per video, each of which performs meaningful recursive work? +3. Can the pipeline produce the agreed VDA `e2e` result contract using + custom images and existing OSMO mechanisms only? +4. Can the lead reconcile results and completion without treating a model's + success claim as proof? + +## Scope and terminology + +`Pipeline` is the user-facing, logical goal plan. An OSMO workflow is a static +execution *capsule*. The dynamic hierarchy is achieved by a running agent task +submitting new workflow capsules through the existing OSMO CLI/API; it never +adds tasks to an already submitted workflow. + +The [locked topology](references/locked-topology.md) is the POC authority: + +- One long-lived **lead-agent workflow** owns the one overarching VDA goal. +- The lead creates a Swift-backed run workspace, delegates one bounded + **environment-pipeline workflow**, and waits for its `environment-ready` + result before video fan-out. +- The environment pipeline verifies the content-addressed model-artifact + workspace. On a cache miss it dynamically submits exactly one deterministic + **model-artifact-materializer workflow**. +- The lead then submits one bounded **video-pipeline workflow** per approved + video, also an agentic loop. +- Each video agent submits original labeling and augmentation in parallel, then + submits augmented labeling only after valid augmentation evidence. +- Each stage workflow contains one deterministic GPU task, runs a pinned + upstream PAIDF image directly, and has no agent loop or delegation authority. +- Preflight is a deterministic action within the relevant agent. There is no + static setup workflow: only the environment pipeline may admit a deterministic + materializer on a cache miss. +- Each video agent publishes a shared video-stage bundle; every stage performs + `init -> execute -> validate -> result` inside its one task without installing + dependencies. +- The target is the VDA `e2e` output contract: original labels, augmented + video, and augmented labels for every video, not reuse of the reference YAML. + +It does not attempt to build a UI, change OSMO services, create static or +unbounded preflight/setup workflows, recursively delegate beyond pipeline agent +to deterministic task, install arbitrary packages at VDA task runtime, or give +deterministic workers agentic authority. + +## Plan sequence + +For the exact static capsule schema, OSMO commands, and execution sequence, see +[Workflow overview](references/overview.md). + +The accepted execution hierarchy and admission rules are in +[Locked topology](references/locked-topology.md). It supersedes earlier local-lead and +generic-worker examples in this directory. + +1. [Architecture and contracts](references/00-architecture-and-contracts.md) defines the + POC boundary, durable files, and the smallest plan/result contracts. +2. [Lead and pipeline compiler](references/01-local-lead-and-pipeline.md) makes the + OSMO-hosted lead produce, inspect, revise, and compile the plan. +3. [Runtime environment construction](references/02-runtime-environments.md) resolves + skills, tools, MCP configuration, and plugins into an immutable image. +4. [Worker execution and fan-out](references/03-worker-execution-and-fanout.md) runs a + bounded agent in OSMO and verifies controlled child submission. +5. [Validation and demo](references/04-validation-and-demo.md) defines the evidence gates + required before expanding the prototype. +6. [Vocabulary and existing interfaces](references/05-vocabulary-and-interfaces.md) + defines the canonical POC terms, actions, and reuse boundaries. + +Each plan has a build sequence and validation gates. Later plans may be +designed in parallel, but implementation proceeds only when the preceding gate +is satisfied. + +## Success condition + +From one user request, the OSMO-hosted lead produces an approved plan; starts +one environment-pipeline agent and, after `environment-ready`, one +video-pipeline agent per input video; each video agent dynamically executes the +original-label, augmentation, and augmented-label sequence; and the run +produces the VDA `e2e` result contract with recorded lineage and evidence. + +## Related design + +- [Overview](../../../01-overview.md) +- [Lifecycle](../../../02-lifecycle.md) +- [Lead agent](../../../04-lead-agent.md) +- [Workflow construction](../../../06-workflow-construction.md) +- [Agent construction](../../../07-agent-construction.md) +- [Agent-to-agent communication](../../../08-agent-agent-communication.md) diff --git a/projects/agents/poc/skills/vda-two-video-poc/SKILL.md b/projects/agents/poc/skills/vda-two-video-poc/SKILL.md new file mode 100644 index 000000000..f6389f424 --- /dev/null +++ b/projects/agents/poc/skills/vda-two-video-poc/SKILL.md @@ -0,0 +1,186 @@ +--- +name: vda-two-video-poc +description: Run the accepted two-video Video Data Augmentation demonstration through the generic OSMO agentic-workflow framework. Use only when the task explicitly requests this VDA POC, its model-artifact cache, PAIDF stages, or its locked output contract. +--- + +# VDA two-video POC + +This is an opt-in domain skill, not part of the agentic-workflow framework. +The framework never loads it implicitly. A task that requests this demo must +name this public, commit-pinned skill path in its task-scoped instructions and +read this file and the listed references before planning or delegation. + +Complete the locked VDA `e2e` demonstration for exactly the two inputs below. +Follow the accepted topology and contracts in +[`references/locked-topology.md`](references/locked-topology.md), +[`references/00-architecture-and-contracts.md`](references/00-architecture-and-contracts.md), +and [`references/02-runtime-environments.md`](references/02-runtime-environments.md). Do not change those +constraints or substitute inputs, models, images, or storage locations. + +## Immutable inputs + +| Video | OSMO data URL | Bytes | SHA-256 | +| --- | --- | ---: | --- | +| `03_IllegalOccupation_020_10FPS.mp4` | `swift://pdx.s8k.io/AUTH_team-osmo/dev/fernandol/agents_poc/datasets/vda-poc-two-video/03_IllegalOccupation_020_10FPS.mp4` | 553882 | `2dd910428c16c264c7eff6882ae6f71559950981b4cd32c5f99e37163c808c1b` | +| `goal_0086_0hz_6sec.mp4` | `swift://pdx.s8k.io/AUTH_team-osmo/dev/fernandol/agents_poc/datasets/vda-poc-two-video/goal_0086_0hz_6sec.mp4` | 5636273 | `2c5f0beff432de6cdcd32af8fb3497ae4eb5ee5d732e91ebd577899bbfadd5bb` | + +The input source is Hugging Face +`nvidia/video-data-augmentation-demo` at +`0b914ba2d32bd6991e73e31f0de7c9d381076e17`; the Swift mirror has already +been verified against this manifest. + +## Scheduling and recovery policy + +Every agent that submits a capsule must inspect all OSMO pools and resource +profiles accessible to the user with the OSMO CLI before that submission. From +the compatible eligible choices, select the best-fit pool and platform for its +specific capsule based on its declared resource profile, pinned-image platform +compatibility, and current observed scheduling evidence. The creator's pool is +not a default or a constraint on a child. Record the considered eligible +choices, selected pool, platform, priority, workflow ID, output URL, and reason +for the selection in durable evidence. A selection is frozen for that immutable +capsule only; a later replacement repeats this selection and may use a different +verified eligible pool or platform. + +Set the priority from the capsule's declared resource profile: submit every +CPU-only capsule at `HIGH` priority (the lead, environment pipeline, +per-video pipelines, CPU-only materializer, and equivalent CPU-only work), and +submit every GPU-requesting deterministic VDA capsule at `LOW` priority +(PAIDF auto-labeling, PAIDF augmentation, and equivalent GPU work). Low +priority is intentionally allowed to bypass normal quota when physical capacity +is idle and may be preempted. Do not alter OSMO pools, profiles, quotas, +credentials, or service configuration. + +There is no numeric retry or resubmission limit for this run. A pending task, +temporary capacity or quota block, preemption, or failed child is a known +non-terminal condition: preserve the evidence, reconcile the existing +workflow, then recover or retry. If a non-running child is demonstrably blocked +and a different verified eligible pool could make progress, you are authorized +to cancel that child without `--force`, wait for its terminal state, and submit +a new immutable replacement. Never cancel a running child merely to chase +capacity, and never submit a replacement before the prior attempt is terminal. +If no safe replacement exists yet, return `Retrying` and reconcile again after +the runtime's controlled delay. Ask the human only when the next safe action is +genuinely ambiguous after inspecting the frozen contracts, evidence, and OSMO +state. + +## Immutable recovery rules for this run + +Use a new `RUN_ID` and a new content-addressed cache lock for this run. Never +reuse, overwrite, or repair the earlier cache generation. The cache lock must +cover the current source-manifest SHA-256, materializer-script SHA-256, +consumer-readiness-verifier SHA-256, and consumer-ready publication policy. + +The VDA-specific source of truth is this skill's public repository at this +task's exact `STATIC_REPOSITORY_REF`: + +```text +projects/agents/poc/skills/vda-two-video-poc/assets/model-artifact-materializer/ + model-artifact-sources-v1.json + materialize-model-artifacts.sh + verify-vda-cache.py +``` + +The generic framework kit deliberately does not include these assets. When +their bytes are needed, clone `STATIC_REPOSITORY_URL` at exactly +`STATIC_REPOSITORY_REF`, verify the detached commit, and use the skill paths +above. Do not replace them with copied, invented, or differently-versioned +inline code. + +The environment pipeline may issue `environment-ready.json` only after it has +verified the materializer's root-level `cache-manifest.json` and +`cache-result.json`, their SHA-256 values, and the remote object inventory +required by the v2 manifest. The v2 manifest intentionally excludes only the +declared transient Hugging Face metadata; do not require excluded `.locks`, +`xet`, `.agent_harnesses.json`, `.no_exist`, or `trees/*.json` objects. + +Write `environment-ready.json` with these exact, explicit fields: + +```json +{ + "schemaVersion": "v2", + "outcome": "Completed", + "cacheLock": "", + "artifactRootUrl": "swift://.../model-artifacts/vda//", + "payloadUrl": "swift://.../model-artifacts/vda//", + "manifestUrl": "swift://.../model-artifacts/vda//cache-manifest.json", + "manifestSha256": "<64-lowercase-hex>", + "resultUrl": "swift://.../model-artifacts/vda//cache-result.json" +} +``` + +`artifactRootUrl` and `payloadUrl` are both explicit even when this v2 layout +uses the same prefix. Downstream code must use the values as written; it must +not append `cache/`, rebuild a URL from the lock, or copy their values from a +parent's prose. + +The lead passes each video child only `environmentReadyUrl` and +`environmentReadySha256`. Each video child downloads and verifies that document +before using its exact fields. It repeats the same reference-only rule for +every deterministic stage contract. + +Before running PAIDF inference, each deterministic stage must materialize its +declared cache payload locally, verify its manifest binding, and execute the +pinned `verify-vda-cache.py` from its stage bundle inside the PAIDF image: + +```text +auto-label stages: verify-vda-cache.py --component auto-labeling +augmentation stage: verify-vda-cache.py --component augmentation +``` + +The stage bundle records the verifier SHA-256 and it must equal the +`consumerReadinessVerifier.sha256` in the verified cache manifest. A failed +consumer-readiness check is a typed stage failure and must not start expensive +inference. + +The video-stage bundle must materialize each application configuration at the +path selected by its worker, and record that resolved path in the immutable +stage contract. In particular, an augmentation worker must not infer a +per-video `configs/