Skip to content

Feature/icp agent runtime phases 0 2 - #18

Merged
HiveForensicsAI merged 2 commits into
mainfrom
feature/icp-agent-runtime-phases-0-2
Aug 3, 2026
Merged

Feature/icp agent runtime phases 0 2#18
HiveForensicsAI merged 2 commits into
mainfrom
feature/icp-agent-runtime-phases-0-2

Conversation

@HiveForensicsAI

Copy link
Copy Markdown
Contributor

Summary

Validation

  • Rust checks
  • TypeScript checks
  • Contracts/fixtures updated together
  • Pack authority remains minimal
  • No generated output or secrets

Embed knolo-agent-core/scheduler in an ICP canister host with deterministic
control-plane execution (Phase 1) and pack-gated tools, ic-llm, knowledge
retrieval, timers, and cycles/budget observation (Phase 2). Document
constraints and ADR-001; ship a local dfx example and CHANGELOG entry.
Add upgrade-safe ic-stable-structures persistence, runtime limits and
caller hardening, multi-agent handoff, scripts/templates, TS client, and
cost/security docs for the ICP agent canister.
@HiveForensicsAI
HiveForensicsAI merged commit 99558a5 into main Aug 3, 2026
8 of 20 checks passed
@HiveForensicsAI
HiveForensicsAI deleted the feature/icp-agent-runtime-phases-0-2 branch August 3, 2026 15:27

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 217780ae52

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +514 to +517
let resolved = ENGINE.with(|e| std::mem::take(&mut *e.borrow_mut()));
let mut eng = resolved;
let result = effects::resolve_one_effect(&mut eng, &execution_id).await;
ENGINE.with(|e| *e.borrow_mut() = eng);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep the live engine installed across effect awaits

When LLM or knowledge resolution reaches the .await, ICP may process another message while the thread-local contains AgentEngine::default(). During that interval queries report no definition, authorization reads the default open limits, and mutations from an interleaved update are discarded when this code overwrites the entire engine after the await. Preserve shared configuration/state across the await and merge only the resolved execution result.

Useful? React with 👍 / 👎.

let state = parse_state(state_json)?;
let id = ExecutionId::from_str(execution_id)
.map_err(|e| CoreError::Host(format!("invalid execution_id: {e}")))?;
let report = self.run_from_start(&id, state, None, BTreeMap::new())?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Enforce projected authority on accepted handoffs

When an envelope narrows max_steps, max_cost_micros, or allowed capabilities, the child is nevertheless started through the normal loaded graph and full pack policy; authority_projection is only copied into the later audit record. A child excluding a tool or granting five steps can therefore use that tool and run up to the graph's larger limits, defeating the handoff's least-authority boundary. Pass the validated child authority into execution and policy enforcement.

Useful? React with 👍 / 👎.

Comment on lines +595 to +597
if let Some(json) = snap.definition_json {
eng.load_definition(&json)
.map_err(|err| format!("reload definition: {err}"))?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Restore persisted fields after reloading the definition

On every upgrade with a loaded definition, load_definition clears budget and handoffs after those fields were restored on lines 592–593. Executions are reassigned afterward, but the persisted budget counters and handoff audit records remain empty, so get_budget/get_handoff lose durable data and budget accounting resets across upgrades. Reload the definition before applying the snapshot fields that it clears.

Useful? React with 👍 / 👎.

.and_then(Value::as_str)
.unwrap_or("Say hello from Knolo ICP agent.")
.to_string();
let (text, tokens, cost) = llm_prompt(&prompt).await?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Honor llm_enabled before invoking ic-llm

When a definition sets host.llm_enabled to false but reaches an await_llm node, this branch still invokes ic_llm::prompt on wasm and spends cycles. The flag is currently used only for inspection text, so the advertised disable control has no runtime effect; reject or leave the execution suspended before calling the provider when it is false.

AGENTS.md reference: AGENTS.md:L15-L15

Useful? React with 👍 / 👎.

Comment on lines +293 to +297
async fn continue_effects(execution_id: String) -> RunReportDto {
if let Err(err) = require_run_auth() {
return RunReportDto::err(execution_id, err.message);
}
let finished = continue_effects_inner(execution_id).await;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Apply the cycles reserve guard to effect continuation

When the balance falls below a configured min_cycles_reserve after an execution has suspended for LLM or retrieval, callers can invoke continue_effects and initiate the costly operation because this update omits the guard used by start_execution, step, resume, and handoff methods. This bypasses the reserve precisely on the endpoint dedicated to spending cycles; run require_cycles_guard before draining effects.

AGENTS.md reference: AGENTS.md:L15-L15

Useful? React with 👍 / 👎.

Comment on lines +475 to +476
async fn continue_effects_inner(execution_id: String) -> RunReportDto {
loop {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Stop effect draining at max_effect_rounds

When host.max_effect_rounds is set below the number of pending effects—even zero—this unconditional loop continues resolving until termination or HITL and never reads the configured bound. All public canister paths call this function rather than the separate bounded helper in effects.rs, so the documented per-message instruction guard is ineffective. Count resolutions here and return the suspended record once the configured maximum is reached.

AGENTS.md reference: AGENTS.md:L15-L15

Useful? React with 👍 / 👎.

HiveForensicsAI added a commit that referenced this pull request Aug 3, 2026
Land remaining CI-green fixes after #18: clippy cleanups in knolo-agent-icp, hygiene without ripgrep, and FUTURE.md legacy wording.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants