Skip to content

feat: composable context-intelligence behaviors — logging / analytics / full#27

Open
colombod wants to merge 11 commits into
mainfrom
feat/spike-readonly-behaviour
Open

feat: composable context-intelligence behaviors — logging / analytics / full#27
colombod wants to merge 11 commits into
mainfrom
feat/spike-readonly-behaviour

Conversation

@colombod
Copy link
Copy Markdown
Collaborator

@colombod colombod commented May 30, 2026

Summary

Splits context-intelligence into three composable behaviors so consumers pick exactly the capabilities they need — instrumentation, read/query, or both.

Behavior Provides Event-capture hook Analytics (agents/tools/skills/mode)
context-intelligence-logging event-capture hook only
context-intelligence-analytics graph-analyst + session-navigator + tools + skills + design mode
context-intelligence (full) composes both via includes: ✅ (registered once)

Why

Previously the hook was inlined in the full behavior, so a consumer wanting pure telemetry had to pull in the entire analytics surface, and there was no symmetric "logging-only" counterpart to the analytics-only behavior. Splitting the producer (hook) from the consumer (agents/tools) makes them independently composable.

Changes

  • NEW behaviors/context-intelligence-logging.yaml — hook-only behavior (hook-context-intelligence module + full config), distinct bundle name.
  • behaviors/context-intelligence.yaml — no longer inlines the hook; now includes: analytics + logging. Composition is equivalent to before, with the hook registered exactly once.
  • behaviors/context-intelligence-analytics.yaml — unchanged.
  • context/context-intelligence-awareness.md — documents the three composition modes.
  • Tests — test_bundle.py / test_module_loading.py: hook-shape assertions now target the logging behavior; added full-behavior composition checks (includes both; no inline hook) and logging-behavior structure checks.

Verification

  • Unit suite: 347 passed. (4 pre-existing test_skill_fetcher_mount failures are unrelated to this change — reproduced on the branch with these changes stashed.)
  • DTU behavioral tests (local branch mirrored to Gitea; three live environments), asserted against each session's authoritative session:config composition record:
behavior CI hook (events.jsonl) graph-analyst session-navigator
logging-only ✅ ×1
full ✅ ×1
analytics-only

Full behavior confirmed to register the hook exactly once despite composing both behaviors.

Also in this PR

  • Earlier main merge resolving conflicts in config_resolver.py (kept the HookConfigResolver rename + DRY _env import; adopted main's _DEFAULT_EXCLUDE_EVENTS = ["llm:stream_*delta"] default) and test_config_resolver.py.

Diego Colombo and others added 11 commits May 30, 2026 03:28
… hook layers

Create context-intelligence-nav behavior with navigation/exploration/tool-design capabilities (agents, modes, tools, skills, context) WITHOUT session telemetry hook.

Rewrite context-intelligence.yaml to use nested composition: includes context-intelligence-nav behavior + adds hook-context-intelligence module only.

This spike enables composing context-intelligence navigation into other apps without mandatory event capture. Full behavior still provides both query capabilities AND telemetry.

Config resolver investigation confirmed hooks: and tools: use identical resolution (same parser, same _validate_module_list(), same SimpleSourceResolver), so nested composition pattern works cleanly.

Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Implement composable context-intelligence to support read-only analysis without
event hooks. This allows apps to embed context navigation/querying/analysis
features without requiring the event capture hook infrastructure.

Key changes:

- NEW: context_intelligence/standalone_resolver.py
  StandaloneConfigResolver reads server_url, api_key, workspace, base_path
  from AMPLIFIER_CONTEXT_INTELLIGENCE_* env vars and ~/.amplifier/settings.yaml.
  Provides fallback for tools when hook is not mounted.

- Rename: behaviors/context-intelligence-nav.yaml -> context-intelligence-analytics.yaml
  Nav-only composition: agents + mode + tools + skills, no hook.
  Enables analytics-only deployment (querying existing session data).

- MODIFIED: tool-graph-query, tool-blob-read
  Replaced "hook not configured" error with StandaloneConfigResolver fallback.
  Tools now work in analytics-only mode.

- MODIFIED: hook config_resolver.py
  Added AMPLIFIER_CONTEXT_INTELLIGENCE_BASE_PATH env var to resolution chain
  (between coordinator.config and hardcoded default). Allows base_path override.

- MODIFIED: behaviors/context-intelligence.yaml
  Now composes from context-intelligence-analytics (nav) + hook.
  Nested composition allows selective opt-in to event capture.

- UPDATED: context-intelligence-awareness.md, session-navigator.md
  Documented two composition modes and BASE_PATH env var resolution.
  Session-navigator now resolves BASE_PATH from env at investigation start.

Composition strategy (Option 1: nested YAML includes):
- context-intelligence-analytics.yaml: read-only analysis (no hook)
- context-intelligence.yaml: full feature set (analytics + hooks)
  Resolves via identical code paths for both tools and hooks.

Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
- Remove StandaloneConfigResolver (wrong abstraction per code review)
- Pass config dict to tools instead of bypassing mount() convention
- Add base_path as configurable env var (AMPLIFIER_CONTEXT_INTELLIGENCE_BASE_PATH)
- Update graph-analyst to interpolate server_url, api_key, workspace from env vars
- Replace all hardcoded ~/.amplifier/projects paths with $BASE_PATH in session-navigator

This enables analytics-only behavior (context-intelligence-analytics.yaml)
to work without the hook, using inline config fallback in tools instead of
depending on coordinator capabilities registered at hook mount time.

Fixes:
- modules/tool-graph-query: GraphQueryTool.__init__ accepts config dict, execute()
  uses config fallback when hook capability is absent
- modules/tool-blob-read: BlobReadTool.__init__ accepts config dict, same fallback
- behaviors/context-intelligence.yaml: expose base_path via env var interpolation
- agents/session-navigator.md: parameterize storage paths for multi-tenant usage

Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
…lobReadTool

Add TestAnalyticsOnlyMode class to both tool test files to cover the
fallback path introduced when the context_intelligence.config_resolver
capability is absent (no hook mounted).

- test_graph_query_tool.py: 3 new tests
  - test_analytics_only_success: verifies config dict drives AsyncCIClient
    construction (server_url, api_key) and workspace forwarded to cypher()
  - test_analytics_only_workspace_defaults_to_default: no workspace key in
    config falls back to 'default'
  - test_analytics_only_no_server_url_returns_error: documents error message
    is 'server URL not configured' (not 'hook not configured')

- test_blob_read_tool.py: 2 new tests
  - test_analytics_only_success: verifies config dict drives AsyncCIClient
    construction with correct server_url and api_key
  - test_analytics_only_no_server_url_returns_error: documents error message
    is 'server URL not configured' (not 'hook not configured')
Split configuration resolution into HookConfigResolver (full lifecycle context)
and ToolConfigResolver (analytics-only mode) with shared resolution chain.

**Core changes:**
- Extract shared _ENV_PREFIX constant and _env() helper to context_intelligence.config
- Rename ConfigResolver → HookConfigResolver with explicit semantics
- Add ToolConfigResolver for analytics-only execution path (4-level resolution chain)
- Update both tools to lazily instantiate ToolConfigResolver in execute() when hook unavailable

**Resolution chain (identical for both resolvers):**
  1. mount() config dict / tool._config (highest priority)
  2. coordinator.config
  3. AMPLIFIER_CONTEXT_INTELLIGENCE_{SERVER_URL,API_KEY,WORKSPACE} env vars
  4. ~/.amplifier/settings.yaml
  5. defaults (workspace only: 'default', others: None)

**Key behavioral differences:**
- HookConfigResolver.workspace auto-derives from session.working_dir (hook lifecycle only)
- ToolConfigResolver.workspace falls back to env var / "default" (no session context)
- Both resolve server_url and api_key identically via 4-level chain
- Workspace caching and lazy property evaluation preserved in both

**Testing:**
- Rename all ConfigResolver → HookConfigResolver refs in test_config_resolver.py (70+ usages)
- Fix 4 tests that weren't clearing env vars before None assertions
- Add test_tool_resolver.py: 33 tests covering ToolConfigResolver chain, caching, and interface
- Coverage: analytics-only success paths, env var precedence, coordinator.config fallthrough
- All 172 tests passing, 0 failures

**Documentation:**
- Update README.md, all docs, diagrams (config-resolution.dot, logging-handler-flow.dot)
- Update agents/graph-analyst.md, skills/context-intelligence-session-navigation/SKILL.md
- Clarify dual-path library template for mount() config capture pattern

Generated with Amplifier
The capability key 'context_intelligence.config_resolver' is renamed to
'context_intelligence.hook_config_resolver' to explicitly document that
the tool is looking for the HOOK's resolver before falling back to
ToolConfigResolver.

This makes the intent self-documenting: reading
'get_capability("context_intelligence.hook_config_resolver")' in the
code now clearly signals the lookup behavior to maintainers.

Changes across 6 modules and tests:
- modules/hook-context-intelligence: register/unregister calls
- modules/tool-graph-query: get_capability call + test
- modules/tool-blob-read: get_capability call
- README.md: documentation example
Mechanical ruff formatting applied to test files after ConfigResolver →
HookConfigResolver rename. No logic changes, formatting only.

- modules/hook-context-intelligence/tests/test_config_resolver.py
- modules/hook-context-intelligence/tests/test_mount_dispatcher.py
- modules/tool-graph-query/tests/test_graph_query_tool.py

Fixes CI Lint failure.
…e analytics

Completes code review cleanup for the composable analytics behavior PR:

- Rename `context_intelligence.config_resolver` ->
  `context_intelligence.hook_config_resolver` across all docstrings,
  comments, README, and test assertion messages (executable code was
  already renamed in the PR)
- Add `# type: ignore[attr-defined]` suppression on `_env` private
  import in context_intelligence/tool_resolver.py to fix pyright error
  (mirrors existing suppression in config_resolver.py)
- Fix type annotation in blob_read_tool.py (`self._resolver: Any` ->
  `Any | None`) to match graph-query tool
- Add late-mount integration test proving tool upgrades from
  ToolConfigResolver fallback to hook resolver when hook mounts after
  first tool execute()

Note: Two other review items (blob-read path-traversal guard and
server_url scheme allowlist) are intentionally deferred for deeper
analysis.

Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Resolve conflicts in hook-context-intelligence config_resolver.

- config_resolver.py: keep the branch's HookConfigResolver rename and its
  DRY import of _env from context_intelligence.config; adopt main's new
  _DEFAULT_EXCLUDE_EVENTS = ["llm:stream_*delta"] default (commit a9ce2a8,
  align exclude_events with hooks-logging). Dropped main's local _ENV_PREFIX
  and local _env() since _env is now imported from the shared config module.
- test_config_resolver.py: keep `import fnmatch` for the new exclude_events
  tests; unify all resolver constructor calls to HookConfigResolver.

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
…viors

Add a dedicated hook-only `context-intelligence-logging` behavior and
refactor the full `context-intelligence` behavior to compose it alongside
the existing analytics behavior via `includes:`. Consumers can now pick
granularity: logging-only (instrument the session), analytics-only
(read/query, no hook), or full (both). The hook is registered exactly once.

- behaviors/context-intelligence-logging.yaml: new hook-only behavior
  (hook-context-intelligence + full config), own bundle name.
- behaviors/context-intelligence.yaml: drop inline hooks; includes
  analytics + logging.
- context/context-intelligence-awareness.md: document three composition modes.
- tests: point hook-shape assertions at the logging behavior; add
  full-behavior composition tests and logging-behavior structure tests.

Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
@colombod colombod changed the title feat: composable analytics behavior — use CI read/query/design without the hook feat: composable context-intelligence behaviors — logging / analytics / full May 31, 2026
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.

1 participant