@namzu/cli 29.0.1 → 29.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +115 -0
- package/README.md +20 -0
- package/dist/browser/commands.d.ts +29 -0
- package/dist/browser/commands.d.ts.map +1 -0
- package/dist/browser/commands.js +361 -0
- package/dist/browser/commands.js.map +1 -0
- package/dist/browser/control.d.ts +79 -0
- package/dist/browser/control.d.ts.map +1 -0
- package/dist/browser/control.js +140 -0
- package/dist/browser/control.js.map +1 -0
- package/dist/browser/describe.d.ts +12 -0
- package/dist/browser/describe.d.ts.map +1 -0
- package/dist/browser/describe.js +27 -0
- package/dist/browser/describe.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +29 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/acp.d.ts.map +1 -1
- package/dist/commands/acp.js +1 -0
- package/dist/commands/acp.js.map +1 -1
- package/dist/commands/browser.d.ts +7 -0
- package/dist/commands/browser.d.ts.map +1 -0
- package/dist/commands/browser.js +16 -0
- package/dist/commands/browser.js.map +1 -0
- package/dist/commands/drain.d.ts +2 -1
- package/dist/commands/drain.d.ts.map +1 -1
- package/dist/commands/drain.js +6 -3
- package/dist/commands/drain.js.map +1 -1
- package/dist/commands/exec-flags.d.ts +2 -1
- package/dist/commands/exec-flags.d.ts.map +1 -1
- package/dist/commands/exec-flags.js +6 -3
- package/dist/commands/exec-flags.js.map +1 -1
- package/dist/commands/exec-json.d.ts.map +1 -1
- package/dist/commands/exec-json.js +2 -1
- package/dist/commands/exec-json.js.map +1 -1
- package/dist/commands/exec.d.ts.map +1 -1
- package/dist/commands/exec.js +2 -1
- package/dist/commands/exec.js.map +1 -1
- package/dist/commands/host-queries.d.ts.map +1 -1
- package/dist/commands/host-queries.js +10 -3
- package/dist/commands/host-queries.js.map +1 -1
- package/dist/commands/schedule.d.ts +9 -0
- package/dist/commands/schedule.d.ts.map +1 -0
- package/dist/commands/schedule.js +126 -0
- package/dist/commands/schedule.js.map +1 -0
- package/dist/commands/serve.d.ts +3 -1
- package/dist/commands/serve.d.ts.map +1 -1
- package/dist/commands/serve.js +5 -3
- package/dist/commands/serve.js.map +1 -1
- package/dist/commands/skills.d.ts +10 -0
- package/dist/commands/skills.d.ts.map +1 -1
- package/dist/commands/skills.js +23 -7
- package/dist/commands/skills.js.map +1 -1
- package/dist/commands/upgrade.d.ts +5 -0
- package/dist/commands/upgrade.d.ts.map +1 -1
- package/dist/commands/upgrade.js +11 -0
- package/dist/commands/upgrade.js.map +1 -1
- package/dist/config/load.d.ts +39 -0
- package/dist/config/load.d.ts.map +1 -1
- package/dist/config/load.js +232 -1
- package/dist/config/load.js.map +1 -1
- package/dist/config/schema.d.ts +78 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js.map +1 -1
- package/dist/config/user-config.d.ts +23 -0
- package/dist/config/user-config.d.ts.map +1 -0
- package/dist/config/user-config.js +48 -0
- package/dist/config/user-config.js.map +1 -0
- package/dist/context/capabilities.d.ts +1 -1
- package/dist/context/capabilities.d.ts.map +1 -1
- package/dist/context/capabilities.js +1 -0
- package/dist/context/capabilities.js.map +1 -1
- package/dist/doctor/checks/browser.d.ts +15 -0
- package/dist/doctor/checks/browser.d.ts.map +1 -0
- package/dist/doctor/checks/browser.js +63 -0
- package/dist/doctor/checks/browser.js.map +1 -0
- package/dist/doctor/checks/index.d.ts +4 -1
- package/dist/doctor/checks/index.d.ts.map +1 -1
- package/dist/doctor/checks/index.js +8 -1
- package/dist/doctor/checks/index.js.map +1 -1
- package/dist/doctor/checks/scheduler.d.ts +10 -0
- package/dist/doctor/checks/scheduler.d.ts.map +1 -0
- package/dist/doctor/checks/scheduler.js +74 -0
- package/dist/doctor/checks/scheduler.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/integrations/notifications/desktop/freedesktop.d.ts +10 -0
- package/dist/integrations/notifications/desktop/freedesktop.d.ts.map +1 -0
- package/dist/integrations/notifications/desktop/freedesktop.js +33 -0
- package/dist/integrations/notifications/desktop/freedesktop.js.map +1 -0
- package/dist/integrations/notifications/desktop/macos.d.ts +6 -0
- package/dist/integrations/notifications/desktop/macos.d.ts.map +1 -0
- package/dist/integrations/notifications/desktop/macos.js +17 -0
- package/dist/integrations/notifications/desktop/macos.js.map +1 -0
- package/dist/integrations/notifications/desktop/sanitize.d.ts +16 -0
- package/dist/integrations/notifications/desktop/sanitize.d.ts.map +1 -0
- package/dist/integrations/notifications/desktop/sanitize.js +49 -0
- package/dist/integrations/notifications/desktop/sanitize.js.map +1 -0
- package/dist/integrations/notifications/desktop/throttle.d.ts +10 -0
- package/dist/integrations/notifications/desktop/throttle.d.ts.map +1 -0
- package/dist/integrations/notifications/desktop/throttle.js +39 -0
- package/dist/integrations/notifications/desktop/throttle.js.map +1 -0
- package/dist/integrations/notifications/desktop/windows-toast.d.ts +23 -0
- package/dist/integrations/notifications/desktop/windows-toast.d.ts.map +1 -0
- package/dist/integrations/notifications/desktop/windows-toast.js +56 -0
- package/dist/integrations/notifications/desktop/windows-toast.js.map +1 -0
- package/dist/integrations/notifications/desktop.d.ts +82 -0
- package/dist/integrations/notifications/desktop.d.ts.map +1 -0
- package/dist/integrations/notifications/desktop.js +198 -0
- package/dist/integrations/notifications/desktop.js.map +1 -0
- package/dist/integrations/resident/session-step.d.ts.map +1 -1
- package/dist/integrations/resident/session-step.js +1 -0
- package/dist/integrations/resident/session-step.js.map +1 -1
- package/dist/integrations/subagents/runtime.d.ts +6 -0
- package/dist/integrations/subagents/runtime.d.ts.map +1 -1
- package/dist/integrations/subagents/runtime.js +14 -5
- package/dist/integrations/subagents/runtime.js.map +1 -1
- package/dist/permissions/browser-sites.d.ts +95 -0
- package/dist/permissions/browser-sites.d.ts.map +1 -0
- package/dist/permissions/browser-sites.js +270 -0
- package/dist/permissions/browser-sites.js.map +1 -0
- package/dist/schedule/build.d.ts +79 -0
- package/dist/schedule/build.d.ts.map +1 -0
- package/dist/schedule/build.js +246 -0
- package/dist/schedule/build.js.map +1 -0
- package/dist/schedule/changes.d.ts +22 -0
- package/dist/schedule/changes.d.ts.map +1 -0
- package/dist/schedule/changes.js +55 -0
- package/dist/schedule/changes.js.map +1 -0
- package/dist/schedule/commands/add.d.ts +24 -0
- package/dist/schedule/commands/add.d.ts.map +1 -0
- package/dist/schedule/commands/add.js +459 -0
- package/dist/schedule/commands/add.js.map +1 -0
- package/dist/schedule/commands/args.d.ts +22 -0
- package/dist/schedule/commands/args.d.ts.map +1 -0
- package/dist/schedule/commands/args.js +80 -0
- package/dist/schedule/commands/args.js.map +1 -0
- package/dist/schedule/commands/confirm-prompt.d.ts +6 -0
- package/dist/schedule/commands/confirm-prompt.d.ts.map +1 -0
- package/dist/schedule/commands/confirm-prompt.js +21 -0
- package/dist/schedule/commands/confirm-prompt.js.map +1 -0
- package/dist/schedule/commands/lifecycle.d.ts +39 -0
- package/dist/schedule/commands/lifecycle.d.ts.map +1 -0
- package/dist/schedule/commands/lifecycle.js +585 -0
- package/dist/schedule/commands/lifecycle.js.map +1 -0
- package/dist/schedule/commands/list.d.ts +33 -0
- package/dist/schedule/commands/list.d.ts.map +1 -0
- package/dist/schedule/commands/list.js +202 -0
- package/dist/schedule/commands/list.js.map +1 -0
- package/dist/schedule/commands/logs.d.ts +7 -0
- package/dist/schedule/commands/logs.d.ts.map +1 -0
- package/dist/schedule/commands/logs.js +106 -0
- package/dist/schedule/commands/logs.js.map +1 -0
- package/dist/schedule/commands/service.d.ts +16 -0
- package/dist/schedule/commands/service.d.ts.map +1 -0
- package/dist/schedule/commands/service.js +458 -0
- package/dist/schedule/commands/service.js.map +1 -0
- package/dist/schedule/daemon/daemon.d.ts +156 -0
- package/dist/schedule/daemon/daemon.d.ts.map +1 -0
- package/dist/schedule/daemon/daemon.js +1248 -0
- package/dist/schedule/daemon/daemon.js.map +1 -0
- package/dist/schedule/daemon/endpoint.d.ts +38 -0
- package/dist/schedule/daemon/endpoint.d.ts.map +1 -0
- package/dist/schedule/daemon/endpoint.js +158 -0
- package/dist/schedule/daemon/endpoint.js.map +1 -0
- package/dist/schedule/daemon/exit.d.ts +8 -0
- package/dist/schedule/daemon/exit.d.ts.map +1 -0
- package/dist/schedule/daemon/exit.js +8 -0
- package/dist/schedule/daemon/exit.js.map +1 -0
- package/dist/schedule/daemon/log.d.ts +12 -0
- package/dist/schedule/daemon/log.d.ts.map +1 -0
- package/dist/schedule/daemon/log.js +53 -0
- package/dist/schedule/daemon/log.js.map +1 -0
- package/dist/schedule/daemon/notify.d.ts +31 -0
- package/dist/schedule/daemon/notify.d.ts.map +1 -0
- package/dist/schedule/daemon/notify.js +89 -0
- package/dist/schedule/daemon/notify.js.map +1 -0
- package/dist/schedule/daemon/retention.d.ts +16 -0
- package/dist/schedule/daemon/retention.d.ts.map +1 -0
- package/dist/schedule/daemon/retention.js +46 -0
- package/dist/schedule/daemon/retention.js.map +1 -0
- package/dist/schedule/daemon/sessions.d.ts +23 -0
- package/dist/schedule/daemon/sessions.d.ts.map +1 -0
- package/dist/schedule/daemon/sessions.js +52 -0
- package/dist/schedule/daemon/sessions.js.map +1 -0
- package/dist/schedule/env.d.ts +28 -0
- package/dist/schedule/env.d.ts.map +1 -0
- package/dist/schedule/env.js +99 -0
- package/dist/schedule/env.js.map +1 -0
- package/dist/schedule/fire/browser-preflight.d.ts +41 -0
- package/dist/schedule/fire/browser-preflight.d.ts.map +1 -0
- package/dist/schedule/fire/browser-preflight.js +73 -0
- package/dist/schedule/fire/browser-preflight.js.map +1 -0
- package/dist/schedule/fire/fire.d.ts +78 -0
- package/dist/schedule/fire/fire.d.ts.map +1 -0
- package/dist/schedule/fire/fire.js +482 -0
- package/dist/schedule/fire/fire.js.map +1 -0
- package/dist/schedule/fire/result.d.ts +13 -0
- package/dist/schedule/fire/result.d.ts.map +1 -0
- package/dist/schedule/fire/result.js +18 -0
- package/dist/schedule/fire/result.js.map +1 -0
- package/dist/schedule/fire/unattended-note.d.ts +22 -0
- package/dist/schedule/fire/unattended-note.d.ts.map +1 -0
- package/dist/schedule/fire/unattended-note.js +46 -0
- package/dist/schedule/fire/unattended-note.js.map +1 -0
- package/dist/schedule/floor.d.ts +116 -0
- package/dist/schedule/floor.d.ts.map +1 -0
- package/dist/schedule/floor.js +1051 -0
- package/dist/schedule/floor.js.map +1 -0
- package/dist/schedule/folder.d.ts +34 -0
- package/dist/schedule/folder.d.ts.map +1 -0
- package/dist/schedule/folder.js +84 -0
- package/dist/schedule/folder.js.map +1 -0
- package/dist/schedule/paths.d.ts +49 -0
- package/dist/schedule/paths.d.ts.map +1 -0
- package/dist/schedule/paths.js +53 -0
- package/dist/schedule/paths.js.map +1 -0
- package/dist/schedule/policy.d.ts +141 -0
- package/dist/schedule/policy.d.ts.map +1 -0
- package/dist/schedule/policy.js +378 -0
- package/dist/schedule/policy.js.map +1 -0
- package/dist/schedule/resume-command.d.ts +36 -0
- package/dist/schedule/resume-command.d.ts.map +1 -0
- package/dist/schedule/resume-command.js +72 -0
- package/dist/schedule/resume-command.js.map +1 -0
- package/dist/schedule/service/detect.d.ts +22 -0
- package/dist/schedule/service/detect.d.ts.map +1 -0
- package/dist/schedule/service/detect.js +29 -0
- package/dist/schedule/service/detect.js.map +1 -0
- package/dist/schedule/service/index.d.ts +48 -0
- package/dist/schedule/service/index.d.ts.map +1 -0
- package/dist/schedule/service/index.js +352 -0
- package/dist/schedule/service/index.js.map +1 -0
- package/dist/schedule/service/launchd.d.ts +24 -0
- package/dist/schedule/service/launchd.d.ts.map +1 -0
- package/dist/schedule/service/launchd.js +84 -0
- package/dist/schedule/service/launchd.js.map +1 -0
- package/dist/schedule/service/manifest.d.ts +44 -0
- package/dist/schedule/service/manifest.d.ts.map +1 -0
- package/dist/schedule/service/manifest.js +16 -0
- package/dist/schedule/service/manifest.js.map +1 -0
- package/dist/schedule/service/names.d.ts +9 -0
- package/dist/schedule/service/names.d.ts.map +1 -0
- package/dist/schedule/service/names.js +22 -0
- package/dist/schedule/service/names.js.map +1 -0
- package/dist/schedule/service/quote.d.ts +24 -0
- package/dist/schedule/service/quote.d.ts.map +1 -0
- package/dist/schedule/service/quote.js +64 -0
- package/dist/schedule/service/quote.js.map +1 -0
- package/dist/schedule/service/runner.d.ts +17 -0
- package/dist/schedule/service/runner.d.ts.map +1 -0
- package/dist/schedule/service/runner.js +31 -0
- package/dist/schedule/service/runner.js.map +1 -0
- package/dist/schedule/service/systemd.d.ts +37 -0
- package/dist/schedule/service/systemd.d.ts.map +1 -0
- package/dist/schedule/service/systemd.js +96 -0
- package/dist/schedule/service/systemd.js.map +1 -0
- package/dist/schedule/service/windows-task.d.ts +51 -0
- package/dist/schedule/service/windows-task.d.ts.map +1 -0
- package/dist/schedule/service/windows-task.js +134 -0
- package/dist/schedule/service/windows-task.js.map +1 -0
- package/dist/schedule/service/wsl.d.ts +57 -0
- package/dist/schedule/service/wsl.d.ts.map +1 -0
- package/dist/schedule/service/wsl.js +111 -0
- package/dist/schedule/service/wsl.js.map +1 -0
- package/dist/schedule/store/atomic.d.ts +43 -0
- package/dist/schedule/store/atomic.d.ts.map +1 -0
- package/dist/schedule/store/atomic.js +135 -0
- package/dist/schedule/store/atomic.js.map +1 -0
- package/dist/schedule/store/claims.d.ts +26 -0
- package/dist/schedule/store/claims.d.ts.map +1 -0
- package/dist/schedule/store/claims.js +57 -0
- package/dist/schedule/store/claims.js.map +1 -0
- package/dist/schedule/store/digest.d.ts +18 -0
- package/dist/schedule/store/digest.d.ts.map +1 -0
- package/dist/schedule/store/digest.js +139 -0
- package/dist/schedule/store/digest.js.map +1 -0
- package/dist/schedule/store/history.d.ts +21 -0
- package/dist/schedule/store/history.d.ts.map +1 -0
- package/dist/schedule/store/history.js +114 -0
- package/dist/schedule/store/history.js.map +1 -0
- package/dist/schedule/store/jobs.d.ts +61 -0
- package/dist/schedule/store/jobs.d.ts.map +1 -0
- package/dist/schedule/store/jobs.js +210 -0
- package/dist/schedule/store/jobs.js.map +1 -0
- package/dist/schedule/store/state.d.ts +19 -0
- package/dist/schedule/store/state.d.ts.map +1 -0
- package/dist/schedule/store/state.js +38 -0
- package/dist/schedule/store/state.js.map +1 -0
- package/dist/schedule/types.d.ts +256 -0
- package/dist/schedule/types.d.ts.map +1 -0
- package/dist/schedule/types.js +9 -0
- package/dist/schedule/types.js.map +1 -0
- package/dist/skills/catalog.d.ts +96 -0
- package/dist/skills/catalog.d.ts.map +1 -0
- package/dist/skills/catalog.js +226 -0
- package/dist/skills/catalog.js.map +1 -0
- package/dist/skills/save.d.ts +148 -0
- package/dist/skills/save.d.ts.map +1 -0
- package/dist/skills/save.js +344 -0
- package/dist/skills/save.js.map +1 -0
- package/dist/skills/store.d.ts +103 -16
- package/dist/skills/store.d.ts.map +1 -1
- package/dist/skills/store.js +227 -30
- package/dist/skills/store.js.map +1 -1
- package/dist/tui/App.d.ts.map +1 -1
- package/dist/tui/App.js +591 -72
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/LiveActivity.d.ts +8 -1
- package/dist/tui/LiveActivity.d.ts.map +1 -1
- package/dist/tui/LiveActivity.js +20 -4
- package/dist/tui/LiveActivity.js.map +1 -1
- package/dist/tui/PermissionOverlay.d.ts +24 -4
- package/dist/tui/PermissionOverlay.d.ts.map +1 -1
- package/dist/tui/PermissionOverlay.js +113 -15
- package/dist/tui/PermissionOverlay.js.map +1 -1
- package/dist/tui/SaveSkillOverlay.d.ts +33 -0
- package/dist/tui/SaveSkillOverlay.d.ts.map +1 -0
- package/dist/tui/SaveSkillOverlay.js +118 -0
- package/dist/tui/SaveSkillOverlay.js.map +1 -0
- package/dist/tui/agent.d.ts +185 -5
- package/dist/tui/agent.d.ts.map +1 -1
- package/dist/tui/agent.js +325 -54
- package/dist/tui/agent.js.map +1 -1
- package/dist/tui/browser-notices.d.ts +33 -0
- package/dist/tui/browser-notices.d.ts.map +1 -0
- package/dist/tui/browser-notices.js +102 -0
- package/dist/tui/browser-notices.js.map +1 -0
- package/dist/tui/permission-review.d.ts.map +1 -1
- package/dist/tui/permission-review.js +53 -4
- package/dist/tui/permission-review.js.map +1 -1
- package/dist/tui/schedule/host-commands.d.ts +34 -0
- package/dist/tui/schedule/host-commands.d.ts.map +1 -0
- package/dist/tui/schedule/host-commands.js +309 -0
- package/dist/tui/schedule/host-commands.js.map +1 -0
- package/dist/tui/schedule/integration.d.ts +62 -0
- package/dist/tui/schedule/integration.d.ts.map +1 -0
- package/dist/tui/schedule/integration.js +145 -0
- package/dist/tui/schedule/integration.js.map +1 -0
- package/dist/tui/schedule/loop-host.d.ts +42 -0
- package/dist/tui/schedule/loop-host.d.ts.map +1 -0
- package/dist/tui/schedule/loop-host.js +153 -0
- package/dist/tui/schedule/loop-host.js.map +1 -0
- package/dist/tui/schedule/resume.d.ts +122 -0
- package/dist/tui/schedule/resume.d.ts.map +1 -0
- package/dist/tui/schedule/resume.js +324 -0
- package/dist/tui/schedule/resume.js.map +1 -0
- package/dist/tui/schedule/startup.d.ts +11 -0
- package/dist/tui/schedule/startup.d.ts.map +1 -0
- package/dist/tui/schedule/startup.js +121 -0
- package/dist/tui/schedule/startup.js.map +1 -0
- package/dist/tui/schedule/tool-host.d.ts +44 -0
- package/dist/tui/schedule/tool-host.d.ts.map +1 -0
- package/dist/tui/schedule/tool-host.js +294 -0
- package/dist/tui/schedule/tool-host.js.map +1 -0
- package/dist/tui/skills/learning.d.ts +74 -0
- package/dist/tui/skills/learning.d.ts.map +1 -0
- package/dist/tui/skills/learning.js +131 -0
- package/dist/tui/skills/learning.js.map +1 -0
- package/dist/tui/skills/suggest-setting.d.ts +22 -0
- package/dist/tui/skills/suggest-setting.d.ts.map +1 -0
- package/dist/tui/skills/suggest-setting.js +55 -0
- package/dist/tui/skills/suggest-setting.js.map +1 -0
- package/dist/tui/skills/suggestion-ledger.d.ts +35 -0
- package/dist/tui/skills/suggestion-ledger.d.ts.map +1 -0
- package/dist/tui/skills/suggestion-ledger.js +52 -0
- package/dist/tui/skills/suggestion-ledger.js.map +1 -0
- package/dist/tui/slashCommands.d.ts +20 -0
- package/dist/tui/slashCommands.d.ts.map +1 -1
- package/dist/tui/slashCommands.js +76 -2
- package/dist/tui/slashCommands.js.map +1 -1
- package/dist/tui/turn-interruption.d.ts +20 -1
- package/dist/tui/turn-interruption.d.ts.map +1 -1
- package/dist/tui/turn-interruption.js +43 -0
- package/dist/tui/turn-interruption.js.map +1 -1
- package/dist/tui/types.d.ts +9 -1
- package/dist/tui/types.d.ts.map +1 -1
- package/package.json +6 -4
- package/skills/README.md +15 -0
- package/skills/browser-automation/SKILL.md +84 -0
- package/skills/schedule-task/SKILL.md +140 -0
- package/skills/skill-creator/SKILL.md +101 -0
package/dist/tui/agent.js
CHANGED
|
@@ -24,10 +24,11 @@ import { countListedResults, webActivityFromInput, webActivityKind, webCallTitle
|
|
|
24
24
|
* `emptySession()` whose `send()` yields a single error event so the UI
|
|
25
25
|
* renders an actionable hint rather than crashing.
|
|
26
26
|
*/
|
|
27
|
-
import { BOOT_EVENT_NAMES, BackgroundJobRegistry, DiskSessionCheckpointStore, DiskSessionLog, DiskTaskStore, EVENT_NAME_ATTRIBUTE, GuardedFetchProvider, InMemorySessionLog, MarkdownMemoryStore, PromptContributionRegistry, ProviderRegistry, SESSION_GOAL_TOOL_NAMES, SessionPaths, ToolRegistry, WebFetchTool, abandonTurn, batchNeedsReview, buildAskUserQuestionTool, buildMemoryTools, buildResidentHistoryTools, buildResidentToolEvidenceTools, buildSessionGoalTools, compactNow, compactSession, createComputerUseTool, createFileReadTracker, createMemoryPromoter, createMemoryRecallStep, createResidentStepContext, createResidentStepContributions, createReviewHandler, createToolPresenter, ensureProject, generateSessionId, generateTenantId, generateTopicId, generateTurnId, getBuiltinTools, isReviewExempt, isTurnInProgressError, query, resumeSession, seedObservationLedger, webGuidanceContribution, withProviderFallback, } from '@namzu/sdk';
|
|
27
|
+
import { BOOT_EVENT_NAMES, BackgroundJobRegistry, DiskSessionCheckpointStore, DiskSessionLog, DiskTaskStore, EVENT_NAME_ATTRIBUTE, GuardedFetchProvider, InMemorySessionLog, MarkdownMemoryStore, PromptContributionRegistry, ProviderRegistry, SCHEDULE_TOOL_NAME, SESSION_GOAL_TOOL_NAMES, SessionPaths, SkillTool, ToolRegistry, WebFetchTool, abandonTurn, batchNeedsReview, buildAskUserQuestionTool, buildMemoryTools, buildResidentHistoryTools, buildResidentToolEvidenceTools, buildSessionGoalTools, compactNow, compactSession, createBrowserTools, createComputerUseTool, createFileReadTracker, createMemoryPromoter, createMemoryRecallStep, createResidentStepContext, createResidentStepContributions, createReviewHandler, createToolPresenter, ensureProject, generateSessionId, generateTenantId, generateTopicId, generateTurnId, getBuiltinTools, isReviewExempt, isTurnInProgressError, query, resolveContextWindow, resumeSession, seedObservationLedger, webGuidanceContribution, withProviderFallback, } from '@namzu/sdk';
|
|
28
28
|
import { SubprocessComputerUseHost } from '@namzu/computer-use';
|
|
29
29
|
import { realpath, stat } from 'node:fs/promises';
|
|
30
30
|
import { parse, resolve } from 'node:path';
|
|
31
|
+
import { createBrowserControl, } from '../browser/control.js';
|
|
31
32
|
import { FileCheckpointStore } from '../checkpoints/store.js';
|
|
32
33
|
import { CHECKPOINTED_TOOLS, withCheckpoints } from '../checkpoints/wrap.js';
|
|
33
34
|
import { configuredPassthroughTools, resolveToolResultScreens, unmatchedPassthroughTools, } from '../config/tool-result-screens.js';
|
|
@@ -62,13 +63,15 @@ import { discoverAgentDefinitions } from '../integrations/subagents/definitions.
|
|
|
62
63
|
import { prepareDelegatedEffort } from '../integrations/subagents/model-effort.js';
|
|
63
64
|
import { resolveSubagentParent } from '../integrations/subagents/parent.js';
|
|
64
65
|
import { replaySavedChildrenFor } from '../integrations/subagents/replay.js';
|
|
65
|
-
import { createSubagentRuntime } from '../integrations/subagents/runtime.js';
|
|
66
|
+
import { createSubagentRuntime, } from '../integrations/subagents/runtime.js';
|
|
66
67
|
import { createSavedAgentHistory, createSavedAgentsStep, } from '../integrations/subagents/saved-agents.js';
|
|
67
68
|
import { cliLogger } from '../logging.js';
|
|
68
69
|
import { formatMemoryDiagnostics } from '../memory/presentation.js';
|
|
69
70
|
import { composeMemoryPrompt, readMemory } from '../memory/store.js';
|
|
70
71
|
import { composeStoredMemoryPrompt, describeCuratedNotesImport, describeMemoryMigration, importCuratedNotes, migrateMemoryOnce, saveTypedNote, } from '../memory/typed.js';
|
|
71
72
|
import { createLiveModeControl, permissionChangeReason, } from '../permissions/live-mode.js';
|
|
73
|
+
import { createSessionSkillCatalog } from '../skills/catalog.js';
|
|
74
|
+
import { SAVE_SKILL_TOOL_NAME } from '../skills/save.js';
|
|
72
75
|
import { projectTurnConversation } from './conversation-history.js';
|
|
73
76
|
import { buildSwitchModelTool } from './model-switch-tool.js';
|
|
74
77
|
import { resolveModelSwitch } from './model-switch.js';
|
|
@@ -287,7 +290,7 @@ async function drainIterator(iterator) {
|
|
|
287
290
|
* Read preferences + run discovery once. Returned context drives the
|
|
288
291
|
* App's lifecycle decision: ready / picker / unhealthy.
|
|
289
292
|
*/
|
|
290
|
-
export async function probeAgentSession() {
|
|
293
|
+
export async function probeAgentSession(options = {}) {
|
|
291
294
|
const read = readPreferences();
|
|
292
295
|
// Bracketed in the log because this is where a boot has stalled without
|
|
293
296
|
// a record on either side: it reads credential files, and on WSL it asks
|
|
@@ -295,7 +298,7 @@ export async function probeAgentSession() {
|
|
|
295
298
|
// and nothing after is this step.
|
|
296
299
|
const discoveryStartedAt = Date.now();
|
|
297
300
|
cliLogger().debug('discovering provider credentials');
|
|
298
|
-
const detected = await discoverProviders();
|
|
301
|
+
const detected = await discoverProviders(options.env ? { env: options.env } : {});
|
|
299
302
|
cliLogger().debug('provider credentials discovered', {
|
|
300
303
|
'namzu.boot.discovery_ms': Date.now() - discoveryStartedAt,
|
|
301
304
|
'namzu.boot.detected_count': detected.length,
|
|
@@ -376,6 +379,9 @@ const EAGER_TOOLS_WHEN_DEFERRED = [
|
|
|
376
379
|
'web_fetch',
|
|
377
380
|
'search_conversation',
|
|
378
381
|
'read_conversation',
|
|
382
|
+
// The skills manifest tells the model to load a skill through this tool;
|
|
383
|
+
// deferring it would make every skill a two-step search first.
|
|
384
|
+
'skill',
|
|
379
385
|
'search_resident_history',
|
|
380
386
|
'read_resident_history',
|
|
381
387
|
'search_resident_tools',
|
|
@@ -483,13 +489,6 @@ function buildToolRegistry(paths, backgroundJobs, checkpoints, screens) {
|
|
|
483
489
|
// after runtime tools are registered. Ordinary CLI task tools are active.
|
|
484
490
|
return { registry, memoryStore, memoryDirectory: directory };
|
|
485
491
|
}
|
|
486
|
-
/** Refresh plugin skill metadata before each provider operation. */
|
|
487
|
-
async function currentPluginSkills(registry) {
|
|
488
|
-
const names = registry.list().map((skill) => skill.metadata.name);
|
|
489
|
-
for (const name of names)
|
|
490
|
-
await registry.load(name, 'metadata');
|
|
491
|
-
return registry.list();
|
|
492
|
-
}
|
|
493
492
|
export async function createAgentSession(prefs, detected, options = {}) {
|
|
494
493
|
const fileObservations = new Map();
|
|
495
494
|
/**
|
|
@@ -906,7 +905,12 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
906
905
|
let lastSendInteractive = false;
|
|
907
906
|
const boundaryFor = (interactive) => ({
|
|
908
907
|
...(sandbox.provider && sandbox.environment
|
|
909
|
-
? {
|
|
908
|
+
? {
|
|
909
|
+
sandbox: {
|
|
910
|
+
environment: sandbox.environment,
|
|
911
|
+
enforced: sandbox.enforced,
|
|
912
|
+
},
|
|
913
|
+
}
|
|
910
914
|
: {}),
|
|
911
915
|
escape: sandboxEscape === 'refuse'
|
|
912
916
|
? 'refused'
|
|
@@ -962,7 +966,9 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
962
966
|
*/
|
|
963
967
|
const storedMemoryPrompt = async () => {
|
|
964
968
|
try {
|
|
965
|
-
return {
|
|
969
|
+
return {
|
|
970
|
+
prompt: composeStoredMemoryPrompt(await memoryStore.readIndex()),
|
|
971
|
+
};
|
|
966
972
|
}
|
|
967
973
|
catch (error) {
|
|
968
974
|
return {
|
|
@@ -1014,6 +1020,26 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1014
1020
|
}));
|
|
1015
1021
|
}
|
|
1016
1022
|
}
|
|
1023
|
+
// The browser: mounted for a surface that asked for it, never launched
|
|
1024
|
+
// here. The host detects the engine now and starts the browser on the
|
|
1025
|
+
// model's first call. Parent session only — sub-agents build their own
|
|
1026
|
+
// registries below and never receive it.
|
|
1027
|
+
const browserPackage = capabilities.find((probe) => probe.specifier === '@namzu/browser');
|
|
1028
|
+
let browserControl;
|
|
1029
|
+
let browserError;
|
|
1030
|
+
if (options.browser && browserPackage?.state === 'present') {
|
|
1031
|
+
try {
|
|
1032
|
+
const { PlaywrightBrowserHost } = await import('@namzu/browser');
|
|
1033
|
+
browserControl = createBrowserControl(PlaywrightBrowserHost, options.browser);
|
|
1034
|
+
registry.register(createBrowserTools(browserControl.host));
|
|
1035
|
+
}
|
|
1036
|
+
catch (error) {
|
|
1037
|
+
browserError = error instanceof Error ? error : new Error(String(error));
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
const browserUnavailable = browserError !== undefined
|
|
1041
|
+
? describeError(browserError)
|
|
1042
|
+
: browserControl?.status().unavailableReason;
|
|
1017
1043
|
// Registered only on the main session path. Sub-agents call
|
|
1018
1044
|
// `buildToolRegistry` directly below, so they never receive these tools.
|
|
1019
1045
|
// Per-send denial further keeps the schemas out of ordinary human turns.
|
|
@@ -1069,6 +1095,9 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1069
1095
|
sandboxReady: sandbox.provider !== undefined,
|
|
1070
1096
|
computerUseReady: computerUseHost !== undefined,
|
|
1071
1097
|
...(computerUseError ? { computerUseError } : {}),
|
|
1098
|
+
browserReady: browserControl !== undefined && browserUnavailable === undefined,
|
|
1099
|
+
...(browserControl ? { browser: browserControl.status() } : {}),
|
|
1100
|
+
...(browserUnavailable !== undefined ? { browserUnavailable } : {}),
|
|
1072
1101
|
});
|
|
1073
1102
|
// URL fetching is separately opt-in and parent-only: children do not
|
|
1074
1103
|
// carry its guarded provider. Independent search is shared below because
|
|
@@ -1096,6 +1125,9 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1096
1125
|
// Best-effort — if the runtime can't stand up, the chat still works.
|
|
1097
1126
|
const delegationScopes = new Map();
|
|
1098
1127
|
const delegationLimits = new Map();
|
|
1128
|
+
// A resumed turn that runs on another model than the session's (a
|
|
1129
|
+
// scheduled job's): its children inherit that model, not the session's.
|
|
1130
|
+
const delegationModels = new Map();
|
|
1099
1131
|
const delegatedInputWaiters = new Map();
|
|
1100
1132
|
if (options.residentHistory) {
|
|
1101
1133
|
const history = options.residentHistory;
|
|
@@ -1193,6 +1225,7 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1193
1225
|
tokenBudget: options.limits?.tokenBudget,
|
|
1194
1226
|
maxIterations: options.limits?.maxIterations,
|
|
1195
1227
|
resolveLimits: (turnId) => delegationLimits.get(turnId),
|
|
1228
|
+
resolveTurnModel: (turnId) => delegationModels.get(turnId),
|
|
1196
1229
|
timeoutMs: options.limits?.timeoutMs,
|
|
1197
1230
|
definitions: discovered.definitions,
|
|
1198
1231
|
// Children log under the parent's `<session-id>/subagents/`; an
|
|
@@ -1382,6 +1415,7 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1382
1415
|
const remaining = await Promise.allSettled([
|
|
1383
1416
|
mcp.close(),
|
|
1384
1417
|
computerUseHost?.dispose(),
|
|
1418
|
+
browserControl?.dispose(),
|
|
1385
1419
|
jobRegistry?.killOwner(jobOwner),
|
|
1386
1420
|
checkpoints.close(),
|
|
1387
1421
|
]);
|
|
@@ -1448,6 +1482,10 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1448
1482
|
// park recorder is supplied.
|
|
1449
1483
|
registry.register(buildAskUserQuestionTool({ resumeHandler: parkQuestion }));
|
|
1450
1484
|
}
|
|
1485
|
+
// The host's own additions, to this registry only: `buildTools` above
|
|
1486
|
+
// builds a child's roster separately, so none of these reach a sub-agent.
|
|
1487
|
+
for (const tool of options.extraTools ?? [])
|
|
1488
|
+
registry.register(tool);
|
|
1451
1489
|
// Task store → query registers task_create / task_update / task_list and
|
|
1452
1490
|
// emits task_created/task_updated, so the agent can track a plan. Tasks
|
|
1453
1491
|
// belong to the session (`<session-id>/tasks/`) and record the turn that
|
|
@@ -1514,14 +1552,35 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1514
1552
|
// refusal closes the MCP processes already opened for this candidate before
|
|
1515
1553
|
// returning an inert session. Sub-agents were built above from their own
|
|
1516
1554
|
// registries, so executable plugins remain a top-level-session capability.
|
|
1555
|
+
// File skills (built-in, ~/.agents, ~/.namzu, and the project's) reach the
|
|
1556
|
+
// model through the kernel's manifest and `skill` tool. Registered BEFORE
|
|
1557
|
+
// the plugin runtime: a runtime that finds the tool already there never
|
|
1558
|
+
// owns it, so disabling the last plugin skill cannot take away the tool
|
|
1559
|
+
// the file skills load through.
|
|
1560
|
+
const skillCatalog = await createSessionSkillCatalog({
|
|
1561
|
+
cwd,
|
|
1562
|
+
...(options.skills ? { config: options.skills } : {}),
|
|
1563
|
+
log: cliLogger(),
|
|
1564
|
+
});
|
|
1565
|
+
// A session that can save a skill loads it next turn through this tool,
|
|
1566
|
+
// even when it started with none.
|
|
1567
|
+
if ((skillCatalog.hasFileSkills || registry.has(SAVE_SKILL_TOOL_NAME)) &&
|
|
1568
|
+
!registry.has(SkillTool.name))
|
|
1569
|
+
registry.register(SkillTool);
|
|
1517
1570
|
let pluginRuntime;
|
|
1518
1571
|
try {
|
|
1519
1572
|
pluginRuntime = await createCliPluginRuntime(options.plugins, registry, cwd, options.hooks);
|
|
1520
1573
|
}
|
|
1521
1574
|
catch (error) {
|
|
1522
|
-
await Promise.allSettled([mcp.close(), computerUseHost?.dispose()]);
|
|
1575
|
+
await Promise.allSettled([mcp.close(), computerUseHost?.dispose(), browserControl?.dispose()]);
|
|
1523
1576
|
return emptySession(describeError(error));
|
|
1524
1577
|
}
|
|
1578
|
+
// Everything is registered by now but the deferred task tools, which no
|
|
1579
|
+
// caller withholds.
|
|
1580
|
+
for (const name of options.withheldTools ?? []) {
|
|
1581
|
+
if (registry.get(name))
|
|
1582
|
+
registry.unregister(name);
|
|
1583
|
+
}
|
|
1525
1584
|
// The session's own lifecycle, for hooks that set up or tear down
|
|
1526
1585
|
// something per session rather than per turn. These two calls belong to no
|
|
1527
1586
|
// turn, so they carry no turn id — nothing is minted to fill the field.
|
|
@@ -1530,6 +1589,14 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1530
1589
|
// is replaced when the conversation is first made durable — and a hook
|
|
1531
1590
|
// given the provisional id could never match it to a turn.
|
|
1532
1591
|
const sessionPlugins = pluginRuntime;
|
|
1592
|
+
// What one turn's prompt manifest and `skill` tool see: the file skills
|
|
1593
|
+
// gated against the tools registered now, merged with the plugins' own.
|
|
1594
|
+
const turnSkillsFor = (turnModel) => skillCatalog.forTurn({
|
|
1595
|
+
toolNames: registry.listNames(),
|
|
1596
|
+
contextWindowTokens: resolveContextWindow(options.compaction?.contextWindowTokens, turnModel)
|
|
1597
|
+
.tokens,
|
|
1598
|
+
...(sessionPlugins ? { pluginSkills: sessionPlugins.skills } : {}),
|
|
1599
|
+
});
|
|
1533
1600
|
let sessionStarted = false;
|
|
1534
1601
|
const announceSessionStart = async () => {
|
|
1535
1602
|
if (!sessionPlugins || sessionStarted)
|
|
@@ -1591,6 +1658,7 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1591
1658
|
: undefined,
|
|
1592
1659
|
mcp.close(),
|
|
1593
1660
|
computerUseHost?.dispose(),
|
|
1661
|
+
browserControl?.dispose(),
|
|
1594
1662
|
jobRegistry?.killOwner(jobOwner),
|
|
1595
1663
|
checkpoints.close(),
|
|
1596
1664
|
]);
|
|
@@ -1647,13 +1715,35 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1647
1715
|
reasoningEffortDefault = undefined;
|
|
1648
1716
|
effortNotice = `Reasoning effort levels could not be established for this session: ${describeError(error)}`;
|
|
1649
1717
|
}
|
|
1718
|
+
/**
|
|
1719
|
+
* The provider a resumed turn runs on when its caller pinned one (a
|
|
1720
|
+
* scheduled job's model): built from this session's credential for that
|
|
1721
|
+
* provider, with no fallback chain, since the job's own run has none.
|
|
1722
|
+
* `undefined` without a pin.
|
|
1723
|
+
*/
|
|
1724
|
+
const pinnedResumeRoute = async (pin, sessionId, signal) => {
|
|
1725
|
+
if (!pin)
|
|
1726
|
+
return undefined;
|
|
1727
|
+
const providerId = pin.provider;
|
|
1728
|
+
const found = findDetected(detected, providerId);
|
|
1729
|
+
if (!found)
|
|
1730
|
+
throw new Error(`the turn runs on ${pin.provider}${pin.model ? `/${pin.model}` : ''} and this session has no credential for ${pin.provider}`);
|
|
1731
|
+
const pinnedModel = pin.model ?? found.entry.defaultModel;
|
|
1732
|
+
await ensureRegistered(providerId);
|
|
1733
|
+
const credential = await currentCredentialFor(providerId, signal);
|
|
1734
|
+
const pinnedProvider = constructProvider(providerId, credential, pinnedModel, { sessionId });
|
|
1735
|
+
const effort = pin.effort;
|
|
1736
|
+
if (effort !== undefined)
|
|
1737
|
+
await prepareDelegatedEffort(pinnedProvider, pinnedModel, signal);
|
|
1738
|
+
return { provider: pinnedProvider, model: pinnedModel, ...(effort ? { effort } : {}) };
|
|
1739
|
+
};
|
|
1650
1740
|
/**
|
|
1651
1741
|
* The kernel's resume with this session's half of the turn attached: the
|
|
1652
1742
|
* provider, the tools, the working directory, the doctrine — the part a
|
|
1653
1743
|
* checkpoint cannot carry. `resumeDurable` and `resumePaused` differ only
|
|
1654
1744
|
* in where the log and its lease come from.
|
|
1655
1745
|
*/
|
|
1656
|
-
const kernelResume = ({ entry, sessionLog, checkpointStore, lease, signal, checkpointId, listener, permissionMode, currentPermissionMode, }) => operations.promise(signal, async (ownedSignal) => {
|
|
1746
|
+
const kernelResume = ({ entry, sessionLog, checkpointStore, lease, signal, checkpointId, listener, permissionMode, currentPermissionMode, pendingDecision, onPermission, rules, reviewHold, model: pinned, systemNote, }) => operations.promise(signal, async (ownedSignal) => {
|
|
1657
1747
|
const selectTaskStore = beginTaskStoreReadout();
|
|
1658
1748
|
// The turn's own limits, as its `turn_started` recorded them.
|
|
1659
1749
|
const resumedLimits = (await readStoredTurnGuards(sessionLog, entry.turnId)) ?? resolveTurnGuards(options.limits);
|
|
@@ -1662,9 +1752,8 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1662
1752
|
// fallback chain has to be built AFTER that so its members do not
|
|
1663
1753
|
// hold a client the refresh just replaced.
|
|
1664
1754
|
await prepareProviderCredential(ownedSignal);
|
|
1665
|
-
const
|
|
1666
|
-
|
|
1667
|
-
: undefined;
|
|
1755
|
+
const route = await pinnedResumeRoute(pinned, entry.sessionId, ownedSignal);
|
|
1756
|
+
const turnSkills = await turnSkillsFor(route?.model ?? model);
|
|
1668
1757
|
const curatedMemory = readMemory(undefined, cwd);
|
|
1669
1758
|
for (const notice of formatMemoryDiagnostics(curatedMemory))
|
|
1670
1759
|
cliLogger().warn(notice);
|
|
@@ -1687,6 +1776,8 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1687
1776
|
options.conversationSessions ? CONVERSATION_EVIDENCE_GUIDANCE : undefined,
|
|
1688
1777
|
environmentPrompt,
|
|
1689
1778
|
memoryPrompt,
|
|
1779
|
+
systemNote,
|
|
1780
|
+
turnSkills.overflowNote,
|
|
1690
1781
|
]
|
|
1691
1782
|
.filter((s) => Boolean(s))
|
|
1692
1783
|
.join('\n\n') || undefined;
|
|
@@ -1708,7 +1799,13 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1708
1799
|
...(recordedModes.has(String(entry.sessionId))
|
|
1709
1800
|
? { recorded: recordedModes.get(String(entry.sessionId)) }
|
|
1710
1801
|
: {}),
|
|
1711
|
-
handlerFor: (mode) =>
|
|
1802
|
+
handlerFor: (mode) => onPermission === undefined && reviewHold !== undefined
|
|
1803
|
+
? makeHoldingResumeHandler(mode, reviewExemptionFor(mode, registry, (input) => subagentRuntime?.launchesReadOnlyAgent(input) === true), { unattendedSandboxEscape }, reviewHold.reason)
|
|
1804
|
+
: makeResumeHandler(
|
|
1805
|
+
// A caller that brings its own prompt (a scheduled turn answered in
|
|
1806
|
+
// the TUI) gets its own latch: the session's "approve all" is not
|
|
1807
|
+
// an answer about a turn another policy started.
|
|
1808
|
+
onPermission ? { all: false } : approval, onPermission, mode, reviewExemptionFor(mode, registry, (input) => subagentRuntime?.launchesReadOnlyAgent(input) === true), { unattendedSandboxEscape }),
|
|
1712
1809
|
});
|
|
1713
1810
|
const resumeHandler = modeControl.handler;
|
|
1714
1811
|
const reviewAllowedCalls = modeControl.reviewAllowedCalls;
|
|
@@ -1718,15 +1815,21 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1718
1815
|
delegatedReviewAllowedCalls.set(entry.turnId, reviewAllowedCalls);
|
|
1719
1816
|
delegationScopes.set(entry.turnId, turnScope);
|
|
1720
1817
|
delegationLimits.set(entry.turnId, resumedLimits);
|
|
1818
|
+
if (route && pinned)
|
|
1819
|
+
delegationModels.set(entry.turnId, {
|
|
1820
|
+
provider: pinned.provider,
|
|
1821
|
+
model: route.model,
|
|
1822
|
+
...(route.effort ? { effort: route.effort } : {}),
|
|
1823
|
+
});
|
|
1721
1824
|
const turnTaskStore = selectTaskStore(turnScope);
|
|
1722
1825
|
try {
|
|
1723
1826
|
return await resumeSession({
|
|
1724
|
-
provider: providerForSession(entry.sessionId),
|
|
1725
|
-
fallbackProviders: fallbackPlan.build(currentToken, entry.sessionId),
|
|
1827
|
+
provider: route?.provider ?? providerForSession(entry.sessionId),
|
|
1828
|
+
fallbackProviders: route ? [] : fallbackPlan.build(currentToken, entry.sessionId),
|
|
1726
1829
|
tools: registry,
|
|
1727
1830
|
pluginManager: pluginRuntime?.manager,
|
|
1728
|
-
skillRegistry:
|
|
1729
|
-
skills:
|
|
1831
|
+
...(turnSkills.registry ? { skillRegistry: turnSkills.registry } : {}),
|
|
1832
|
+
...(turnSkills.manifest ? { skills: turnSkills.manifest } : {}),
|
|
1730
1833
|
taskStore: turnTaskStore,
|
|
1731
1834
|
...(webCapability ? { web: webCapability } : {}),
|
|
1732
1835
|
// The same availability the original turn registered under.
|
|
@@ -1739,9 +1842,12 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1739
1842
|
task_list: 'active',
|
|
1740
1843
|
},
|
|
1741
1844
|
...(subagentRuntime
|
|
1742
|
-
? {
|
|
1845
|
+
? {
|
|
1846
|
+
taskScheduler: await subagentRuntime.gatewayForTurn(entry.turnId),
|
|
1847
|
+
}
|
|
1743
1848
|
: {}),
|
|
1744
|
-
authorizationGate: gateFor(options.rules),
|
|
1849
|
+
authorizationGate: gateFor(rules ?? options.rules),
|
|
1850
|
+
...(pendingDecision ? { pendingDecision } : {}),
|
|
1745
1851
|
compactionConfig: compactionConfigFor(options.compaction),
|
|
1746
1852
|
retainedToolPreviewChars: options.conversationSessions
|
|
1747
1853
|
? (options.compaction?.retainedToolPreviewChars ?? 4_000)
|
|
@@ -1770,7 +1876,8 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1770
1876
|
? { sandboxTeardownTimeoutMs: options.sandbox.teardownTimeoutMs }
|
|
1771
1877
|
: {}),
|
|
1772
1878
|
turnConfig: {
|
|
1773
|
-
model,
|
|
1879
|
+
model: route?.model ?? model,
|
|
1880
|
+
...(route?.effort ? { effort: route.effort } : {}),
|
|
1774
1881
|
...(nativeWebSearch ? { webSearch: nativeWebSearch } : {}),
|
|
1775
1882
|
...(sandbox.provider ? { sandbox: { workspace: sandboxWorkspace } } : {}),
|
|
1776
1883
|
...resumedLimits,
|
|
@@ -1833,6 +1940,7 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1833
1940
|
delegatedReviewAllowedCalls.delete(entry.turnId);
|
|
1834
1941
|
delegationScopes.delete(entry.turnId);
|
|
1835
1942
|
delegationLimits.delete(entry.turnId);
|
|
1943
|
+
delegationModels.delete(entry.turnId);
|
|
1836
1944
|
await subagentRuntime?.releaseTurn(entry.turnId);
|
|
1837
1945
|
}
|
|
1838
1946
|
}
|
|
@@ -1843,12 +1951,13 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1843
1951
|
* headless caller renders a resumed turn exactly as it rendered the first
|
|
1844
1952
|
* segment.
|
|
1845
1953
|
*/
|
|
1846
|
-
const resumePausedStream = ({ turnId, checkpointId, signal, permissionMode, currentPermissionMode, }) => {
|
|
1954
|
+
const resumePausedStream = ({ turnId, checkpointId, signal, permissionMode, currentPermissionMode, pendingDecision, onPermission, rules, reviewHold, model: pinned, systemNote, }) => {
|
|
1847
1955
|
const queue = [];
|
|
1848
1956
|
let wake;
|
|
1849
1957
|
let settled = false;
|
|
1850
1958
|
let failure;
|
|
1851
1959
|
const presenter = createToolPresenter(registry);
|
|
1960
|
+
const readsOnly = declaredReadOnly(registry);
|
|
1852
1961
|
// The log the turn appends to, and its checkpoints beside it.
|
|
1853
1962
|
const sessionLog = DiskSessionLog.at(paths, { sessionId: scope.sessionId });
|
|
1854
1963
|
const outcome = kernelResume({
|
|
@@ -1863,6 +1972,12 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1863
1972
|
...(checkpointId !== undefined ? { checkpointId: checkpointId } : {}),
|
|
1864
1973
|
...(permissionMode ? { permissionMode } : {}),
|
|
1865
1974
|
...(currentPermissionMode ? { currentPermissionMode } : {}),
|
|
1975
|
+
...(pendingDecision ? { pendingDecision } : {}),
|
|
1976
|
+
...(onPermission ? { onPermission } : {}),
|
|
1977
|
+
...(rules ? { rules } : {}),
|
|
1978
|
+
...(reviewHold ? { reviewHold } : {}),
|
|
1979
|
+
...(pinned ? { model: pinned } : {}),
|
|
1980
|
+
...(systemNote ? { systemNote } : {}),
|
|
1866
1981
|
listener: (event) => {
|
|
1867
1982
|
queue.push(event);
|
|
1868
1983
|
wake?.();
|
|
@@ -1888,7 +2003,7 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
1888
2003
|
const next = queue.shift();
|
|
1889
2004
|
if (!next)
|
|
1890
2005
|
break;
|
|
1891
|
-
const mapped = toAgentEvent(next, presenter);
|
|
2006
|
+
const mapped = toAgentEvent(next, presenter, readsOnly);
|
|
1892
2007
|
if (mapped)
|
|
1893
2008
|
yield mapped;
|
|
1894
2009
|
}
|
|
@@ -2005,6 +2120,7 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
2005
2120
|
return mcp.failed;
|
|
2006
2121
|
},
|
|
2007
2122
|
mcpStatus: () => mcp.current(),
|
|
2123
|
+
...(browserControl ? { browser: browserControl } : {}),
|
|
2008
2124
|
configNotices: [
|
|
2009
2125
|
...(capabilityNotice ? [capabilityNotice] : []),
|
|
2010
2126
|
...(effortNotice ? [effortNotice] : []),
|
|
@@ -2012,15 +2128,24 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
2012
2128
|
...(computerUseError
|
|
2013
2129
|
? [`Computer use is unavailable on this device: ${describeError(computerUseError)}`]
|
|
2014
2130
|
: []),
|
|
2131
|
+
...(browserUnavailable !== undefined
|
|
2132
|
+
? [`The browser is unavailable: ${browserUnavailable}`]
|
|
2133
|
+
: []),
|
|
2015
2134
|
...unresolvedNotice.map((line) => `Provider chain: capabilities could not be established for ${line}.`),
|
|
2016
2135
|
...fallbackPlan.notices,
|
|
2017
2136
|
...memoryMigrationNotices,
|
|
2018
2137
|
],
|
|
2019
2138
|
rememberNote: (text, type) => saveTypedNote(memoryStore, text, type),
|
|
2020
|
-
importCuratedNotes: async () => describeCuratedNotesImport(await importCuratedNotes({
|
|
2139
|
+
importCuratedNotes: async () => describeCuratedNotesImport(await importCuratedNotes({
|
|
2140
|
+
store: memoryStore,
|
|
2141
|
+
directory: memoryDirectory,
|
|
2142
|
+
cwd,
|
|
2143
|
+
}), memoryDirectory),
|
|
2021
2144
|
storedMemoryIndex: async () => ({
|
|
2022
2145
|
directory: memoryDirectory,
|
|
2023
|
-
index: await memoryStore.readIndex({
|
|
2146
|
+
index: await memoryStore.readIndex({
|
|
2147
|
+
maxLines: Number.POSITIVE_INFINITY,
|
|
2148
|
+
}),
|
|
2024
2149
|
derived: await memoryStore.readIndex({
|
|
2025
2150
|
maxLines: Number.POSITIVE_INFINITY,
|
|
2026
2151
|
derived: true,
|
|
@@ -2048,7 +2173,7 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
2048
2173
|
const turnScope = { ...scope };
|
|
2049
2174
|
const initialMode = opts?.permissionMode ??
|
|
2050
2175
|
options.permissionMode ??
|
|
2051
|
-
(opts?.onPermission ? 'prompt' : 'auto');
|
|
2176
|
+
(opts?.onPermission || opts?.reviewHold ? 'prompt' : 'auto');
|
|
2052
2177
|
// The mode is read at every decision, so the operator can change it
|
|
2053
2178
|
// while this turn runs (see permissions/live-mode.ts).
|
|
2054
2179
|
const modeControl = createLiveModeControl({
|
|
@@ -2057,7 +2182,9 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
2057
2182
|
...(recordedModes.has(String(turnScope.sessionId))
|
|
2058
2183
|
? { recorded: recordedModes.get(String(turnScope.sessionId)) }
|
|
2059
2184
|
: {}),
|
|
2060
|
-
handlerFor: (mode) =>
|
|
2185
|
+
handlerFor: (mode) => opts?.reviewHold
|
|
2186
|
+
? makeHoldingResumeHandler(mode, reviewExemptionFor(mode, runTools, (input) => subagentRuntime?.launchesReadOnlyAgent(input) === true), { unattendedSandboxEscape }, opts.reviewHold.reason)
|
|
2187
|
+
: makeResumeHandler(approval, opts?.onPermission, mode, reviewExemptionFor(mode, runTools, (input) => subagentRuntime?.launchesReadOnlyAgent(input) === true), { unattendedSandboxEscape }),
|
|
2061
2188
|
});
|
|
2062
2189
|
const resumeHandler = modeControl.handler;
|
|
2063
2190
|
liveModeControls.add(modeControl);
|
|
@@ -2106,9 +2233,7 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
2106
2233
|
// runs — midnight passes, and the agent checks out a branch itself.
|
|
2107
2234
|
// Its text only changes when a fact changes, so it costs a prompt-cache
|
|
2108
2235
|
// miss exactly when a hit would have been a stale claim.
|
|
2109
|
-
const
|
|
2110
|
-
? await currentPluginSkills(pluginRuntime.skills)
|
|
2111
|
-
: undefined;
|
|
2236
|
+
const turnSkills = await turnSkillsFor(model);
|
|
2112
2237
|
// One fork after plugin refresh, held through every iteration of
|
|
2113
2238
|
// this send. Discovery cannot activate another send's schemas.
|
|
2114
2239
|
if (options.toolLoading === 'deferred')
|
|
@@ -2121,7 +2246,11 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
2121
2246
|
}
|
|
2122
2247
|
const storedMemory = await storedMemoryPrompt();
|
|
2123
2248
|
if (storedMemory.notice) {
|
|
2124
|
-
yield {
|
|
2249
|
+
yield {
|
|
2250
|
+
kind: 'context',
|
|
2251
|
+
text: storedMemory.notice,
|
|
2252
|
+
shed: false,
|
|
2253
|
+
};
|
|
2125
2254
|
}
|
|
2126
2255
|
const memoryPrompt = [composeMemoryPrompt(curatedMemory), storedMemory.prompt]
|
|
2127
2256
|
.filter((part) => Boolean(part))
|
|
@@ -2179,7 +2308,10 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
2179
2308
|
authorizeLearningRead: (context) => claimed.has(context.turnId) &&
|
|
2180
2309
|
delegationScopes.get(context.turnId) === turnScope,
|
|
2181
2310
|
})
|
|
2182
|
-
: {
|
|
2311
|
+
: {
|
|
2312
|
+
contributions: createResidentStepContributions(contextOptions),
|
|
2313
|
+
tools: [],
|
|
2314
|
+
};
|
|
2183
2315
|
if (bundle.tools.length) {
|
|
2184
2316
|
// Per-send membership: neither another send nor delegated sessions inherit this tool.
|
|
2185
2317
|
runTools = runTools.fork();
|
|
@@ -2201,7 +2333,12 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
2201
2333
|
const systemPrompt = [
|
|
2202
2334
|
NAMZU_IDENTITY,
|
|
2203
2335
|
residentContext ? undefined : NAMZU_WORKING_DOCTRINE,
|
|
2204
|
-
|
|
2336
|
+
// Advice on delegating, for a session that has the Agent tool:
|
|
2337
|
+
// a scheduled run whose job withholds it would only be told how
|
|
2338
|
+
// to use a tool it was not sent.
|
|
2339
|
+
residentContext || options.withheldTools?.includes(AGENT_LAUNCH_TOOL)
|
|
2340
|
+
? undefined
|
|
2341
|
+
: NAMZU_DELEGATION_DOCTRINE,
|
|
2205
2342
|
!residentContext && opts?.orchestrate ? NAMZU_ORCHESTRATE_DOCTRINE : undefined,
|
|
2206
2343
|
options.conversationSessions ? CONVERSATION_EVIDENCE_GUIDANCE : undefined,
|
|
2207
2344
|
options.toolLoading === 'deferred' ? DEFERRED_TOOL_GUIDANCE : undefined,
|
|
@@ -2214,6 +2351,8 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
2214
2351
|
residentContext ? undefined : environmentPrompt,
|
|
2215
2352
|
residentContext ? undefined : memoryPrompt,
|
|
2216
2353
|
residentContext ? undefined : opts?.extraSystem,
|
|
2354
|
+
residentContext ? undefined : opts?.systemNote,
|
|
2355
|
+
turnSkills.overflowNote,
|
|
2217
2356
|
]
|
|
2218
2357
|
.filter((s) => Boolean(s))
|
|
2219
2358
|
.join('\n\n') || undefined;
|
|
@@ -2246,7 +2385,9 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
2246
2385
|
// when this session is the one bringing it into existence.
|
|
2247
2386
|
let ephemeralLog;
|
|
2248
2387
|
if (options.ephemeral) {
|
|
2249
|
-
ephemeralLog = new InMemorySessionLog({
|
|
2388
|
+
ephemeralLog = new InMemorySessionLog({
|
|
2389
|
+
sessionId: turnScope.sessionId,
|
|
2390
|
+
});
|
|
2250
2391
|
await ensureSessionStarted(ephemeralLog, {
|
|
2251
2392
|
...turnScope,
|
|
2252
2393
|
cwd,
|
|
@@ -2288,8 +2429,8 @@ export async function createAgentSession(prefs, detected, options = {}) {
|
|
|
2288
2429
|
model,
|
|
2289
2430
|
tools: runTools,
|
|
2290
2431
|
pluginManager: pluginRuntime?.manager,
|
|
2291
|
-
skillRegistry:
|
|
2292
|
-
skills:
|
|
2432
|
+
skillRegistry: turnSkills.registry,
|
|
2433
|
+
skills: turnSkills.manifest,
|
|
2293
2434
|
scope: turnScope,
|
|
2294
2435
|
turnId,
|
|
2295
2436
|
paths,
|
|
@@ -2841,6 +2982,7 @@ async function* runTurn({ retainedToolPreviewChars, fileReadTracker, provider, c
|
|
|
2841
2982
|
// matching in the first place: `toAgentEvent` is pure over a `SessionEvent`
|
|
2842
2983
|
// and could not ask a tool anything, so the host guessed from the name.
|
|
2843
2984
|
const presenter = createToolPresenter(tools);
|
|
2985
|
+
const readsOnly = declaredReadOnly(tools);
|
|
2844
2986
|
try {
|
|
2845
2987
|
const events = query({
|
|
2846
2988
|
...(retainedToolPreviewChars !== undefined ? { retainedToolPreviewChars } : {}),
|
|
@@ -2959,7 +3101,7 @@ async function* runTurn({ retainedToolPreviewChars, fileReadTracker, provider, c
|
|
|
2959
3101
|
// receipts and reasoning before the next user turn.
|
|
2960
3102
|
continue;
|
|
2961
3103
|
}
|
|
2962
|
-
const mapped = toAgentEvent(event, presenter);
|
|
3104
|
+
const mapped = toAgentEvent(event, presenter, readsOnly);
|
|
2963
3105
|
if (!mapped)
|
|
2964
3106
|
continue;
|
|
2965
3107
|
yield mapped;
|
|
@@ -3016,6 +3158,41 @@ export function makeResumeHandler(approval, onPermission, mode = onPermission ?
|
|
|
3016
3158
|
unattendedSandboxEscape: escapePolicy.unattendedSandboxEscape ?? 'refuse',
|
|
3017
3159
|
});
|
|
3018
3160
|
}
|
|
3161
|
+
/** Thrown by the holding prompt; never leaves {@link makeHoldingResumeHandler}. */
|
|
3162
|
+
class ReviewHoldSignal extends Error {
|
|
3163
|
+
name = 'ReviewHoldSignal';
|
|
3164
|
+
}
|
|
3165
|
+
/**
|
|
3166
|
+
* The kernel's review policy with a prompt that never answers: every batch
|
|
3167
|
+
* that would be put to a person parks the turn instead (`{ action: 'pause' }`),
|
|
3168
|
+
* which the kernel records durably for a person to answer later.
|
|
3169
|
+
*
|
|
3170
|
+
* The prompt throws and THIS wrapper catches it: a handler that rejects is
|
|
3171
|
+
* turned into `abort` by the kernel (`awaitDecisionOrAbort`), which would end
|
|
3172
|
+
* the turn rather than hold it. The latch is private and never set, so no
|
|
3173
|
+
* earlier answer can approve a later batch.
|
|
3174
|
+
*/
|
|
3175
|
+
export function makeHoldingResumeHandler(mode, exempt, escapePolicy, reason) {
|
|
3176
|
+
const inner = createReviewHandler({
|
|
3177
|
+
mode,
|
|
3178
|
+
prompt: async () => {
|
|
3179
|
+
throw new ReviewHoldSignal(reason);
|
|
3180
|
+
},
|
|
3181
|
+
exempt,
|
|
3182
|
+
remembered: { all: false },
|
|
3183
|
+
unattendedSandboxEscape: escapePolicy.unattendedSandboxEscape ?? 'refuse',
|
|
3184
|
+
});
|
|
3185
|
+
return async (request) => {
|
|
3186
|
+
try {
|
|
3187
|
+
return await inner(request);
|
|
3188
|
+
}
|
|
3189
|
+
catch (error) {
|
|
3190
|
+
if (error instanceof ReviewHoldSignal)
|
|
3191
|
+
return { action: 'pause', reason };
|
|
3192
|
+
throw error;
|
|
3193
|
+
}
|
|
3194
|
+
};
|
|
3195
|
+
}
|
|
3019
3196
|
/**
|
|
3020
3197
|
* Whether a call runs without asking. The kernel's rule: a trusted read-only
|
|
3021
3198
|
* declaration or a named bookkeeping write, never a fetch, never a tool the
|
|
@@ -3038,10 +3215,53 @@ export const AGENT_LAUNCH_TOOL = 'Agent';
|
|
|
3038
3215
|
* An operator who wants every launch asked about writes
|
|
3039
3216
|
* `permissions: { Agent: "ask" }`: an `ask` rule is an explicit review, which
|
|
3040
3217
|
* no exemption skips.
|
|
3218
|
+
*
|
|
3219
|
+
* `save_skill` (the TUI's alone) is not asked about here either, outside
|
|
3220
|
+
* `strict` and `plan`: its own screen shows the whole file and where it goes,
|
|
3221
|
+
* and asks in every mode, `auto` included. A second question in front of it
|
|
3222
|
+
* would ask the same thing with less on the screen. `strict` and `plan` still
|
|
3223
|
+
* refuse it, and an `ask` or `deny` rule for it still applies. Neither is
|
|
3224
|
+
* the `schedule` tool's `create`, `resume` or `delete`, for the same reason
|
|
3225
|
+
* (see {@link confirmsItself}).
|
|
3041
3226
|
*/
|
|
3042
3227
|
export function reviewExemptionFor(mode, registry, launchesReadOnlyAgent) {
|
|
3043
3228
|
return (name, input) => isPromptExempt(registry, name, input) ||
|
|
3044
|
-
(mode !== 'strict' && name === AGENT_LAUNCH_TOOL && launchesReadOnlyAgent(input))
|
|
3229
|
+
(mode !== 'strict' && name === AGENT_LAUNCH_TOOL && launchesReadOnlyAgent(input)) ||
|
|
3230
|
+
(mode !== 'strict' && mode !== 'plan' && confirmsItself(name, input)) ||
|
|
3231
|
+
(mode !== 'strict' &&
|
|
3232
|
+
mode !== 'plan' &&
|
|
3233
|
+
name === SAVE_SKILL_TOOL_NAME &&
|
|
3234
|
+
registry.has(SAVE_SKILL_TOOL_NAME));
|
|
3235
|
+
}
|
|
3236
|
+
/**
|
|
3237
|
+
* The `schedule` tool's `create`, `resume` and `delete`: each puts its own
|
|
3238
|
+
* confirmation in front of the operator, drawn from the host's computation,
|
|
3239
|
+
* and changes nothing unless they choose to. A review before it only asked
|
|
3240
|
+
* "Do you want to run schedule?" over the model's raw arguments, and then the
|
|
3241
|
+
* real question came. `pause` and anything else is reviewed as before; `plan`
|
|
3242
|
+
* and `strict` still refuse, and an `ask` or `deny` rule still decides, since
|
|
3243
|
+
* an explicit review is never exempted.
|
|
3244
|
+
*/
|
|
3245
|
+
export function confirmsItself(name, input) {
|
|
3246
|
+
if (name !== SCHEDULE_TOOL_NAME || typeof input !== 'object' || input === null)
|
|
3247
|
+
return false;
|
|
3248
|
+
const action = input.action;
|
|
3249
|
+
return action === 'create' || action === 'resume' || action === 'delete';
|
|
3250
|
+
}
|
|
3251
|
+
/**
|
|
3252
|
+
* A call's own read-only declaration, as the tool states it for this input.
|
|
3253
|
+
* Not a permission answer (that is `isPromptExempt`): it only says whether a
|
|
3254
|
+
* finished turn changed anything, for the TUI's skill suggestion.
|
|
3255
|
+
*/
|
|
3256
|
+
function declaredReadOnly(registry) {
|
|
3257
|
+
return (toolName, input) => {
|
|
3258
|
+
try {
|
|
3259
|
+
return registry.get(toolName)?.isReadOnly?.(input) === true;
|
|
3260
|
+
}
|
|
3261
|
+
catch {
|
|
3262
|
+
return false;
|
|
3263
|
+
}
|
|
3264
|
+
};
|
|
3045
3265
|
}
|
|
3046
3266
|
/** The exempt roster, sorted, for the surface that has to NAME it. */
|
|
3047
3267
|
export function promptExemptToolNames(registry) {
|
|
@@ -3058,7 +3278,9 @@ export const batchNeedsPrompt = batchNeedsReview;
|
|
|
3058
3278
|
* `null` for events the chat surface doesn't render (iteration markers,
|
|
3059
3279
|
* checkpoints, plan lifecycle, …). Pure — unit-tested.
|
|
3060
3280
|
*/
|
|
3061
|
-
export function toAgentEvent(event, presenter
|
|
3281
|
+
export function toAgentEvent(event, presenter,
|
|
3282
|
+
/** Whether a call only reads, from the tool's own declaration; see `tool-start.readOnly`. */
|
|
3283
|
+
readsOnly) {
|
|
3062
3284
|
switch (event.type) {
|
|
3063
3285
|
case 'hosted_tool': {
|
|
3064
3286
|
const common = {
|
|
@@ -3134,6 +3356,7 @@ export function toAgentEvent(event, presenter) {
|
|
|
3134
3356
|
const web = webActivityFromInput(event.toolName, event.input);
|
|
3135
3357
|
return web ? { web } : {};
|
|
3136
3358
|
})(),
|
|
3359
|
+
...(readsOnly?.(event.toolName, event.input) ? { readOnly: true } : {}),
|
|
3137
3360
|
};
|
|
3138
3361
|
case 'tool_progress':
|
|
3139
3362
|
return {
|
|
@@ -3151,12 +3374,19 @@ export function toAgentEvent(event, presenter) {
|
|
|
3151
3374
|
output: event.result,
|
|
3152
3375
|
});
|
|
3153
3376
|
const detail = viewToLines(view);
|
|
3154
|
-
//
|
|
3155
|
-
// the
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3377
|
+
// The first line is the summary row. It leaves the body only when
|
|
3378
|
+
// the row says all of it: a shortened summary cannot replace the
|
|
3379
|
+
// first line's evidence in expanded or raw output. A first line
|
|
3380
|
+
// up to a few rows long is shown whole, so a note like "A
|
|
3381
|
+
// navigation to … was blocked" is not printed twice, once cut off
|
|
3382
|
+
// on the summary row and again in full underneath.
|
|
3383
|
+
const first = view.kind === 'terminal' && view.output.trim().length > 0
|
|
3384
|
+
? resultToLines(view.output)[0]
|
|
3385
|
+
: undefined;
|
|
3386
|
+
const summary = first !== undefined ? resultSummaryLine(first) : firstLine(event.result);
|
|
3387
|
+
const withoutRepeatedSummary = first !== undefined && detail?.[0] === first && summarySaysAll(first, summary)
|
|
3388
|
+
? detail.slice(1)
|
|
3389
|
+
: detail;
|
|
3160
3390
|
return {
|
|
3161
3391
|
kind: 'tool-end',
|
|
3162
3392
|
output: event.result,
|
|
@@ -3167,6 +3397,9 @@ export function toAgentEvent(event, presenter) {
|
|
|
3167
3397
|
summary,
|
|
3168
3398
|
...(event.durationMs !== undefined ? { durationMs: event.durationMs } : {}),
|
|
3169
3399
|
...(view.kind === 'generic' && view.visibility === 'hidden' ? { hidden: true } : {}),
|
|
3400
|
+
...(event.isError && view.kind === 'generic' && view.outcome === 'cancelled'
|
|
3401
|
+
? { cancelled: true }
|
|
3402
|
+
: {}),
|
|
3170
3403
|
...(view.kind === 'generic' && view.label.length > 0 ? { resultLabel: view.label } : {}),
|
|
3171
3404
|
...(withoutRepeatedSummary && withoutRepeatedSummary.length > 0
|
|
3172
3405
|
? { detail: withoutRepeatedSummary }
|
|
@@ -3176,7 +3409,9 @@ export function toAgentEvent(event, presenter) {
|
|
|
3176
3409
|
if (!kind)
|
|
3177
3410
|
return {};
|
|
3178
3411
|
const results = kind === 'search' && !event.isError ? countListedResults(event.result) : undefined;
|
|
3179
|
-
return {
|
|
3412
|
+
return {
|
|
3413
|
+
web: { kind, ...(results !== undefined ? { results } : {}) },
|
|
3414
|
+
};
|
|
3180
3415
|
})(),
|
|
3181
3416
|
};
|
|
3182
3417
|
}
|
|
@@ -3265,6 +3500,7 @@ export function toAgentEvent(event, presenter) {
|
|
|
3265
3500
|
...(event.failure ? { failure: event.failure } : {}),
|
|
3266
3501
|
...(event.providerError ? { providerError: event.providerError } : {}),
|
|
3267
3502
|
...(event.explanation ? { explanation: event.explanation } : {}),
|
|
3503
|
+
...(event.handoff ? { handoff: event.handoff } : {}),
|
|
3268
3504
|
};
|
|
3269
3505
|
case 'turn_completed':
|
|
3270
3506
|
// Carried through rather than dropped: `turn_failed` fires only from
|
|
@@ -3448,8 +3684,10 @@ export function viewToLines(view) {
|
|
|
3448
3684
|
if (view.output.trim().length === 0)
|
|
3449
3685
|
return undefined;
|
|
3450
3686
|
const lines = resultToLines(view.output);
|
|
3451
|
-
// A single
|
|
3452
|
-
return lines.length === 1 && lines[0]
|
|
3687
|
+
// A single line the summary row shows whole is not repeated under it.
|
|
3688
|
+
return lines.length === 1 && summarySaysAll(lines[0] ?? '', resultSummaryLine(lines[0] ?? ''))
|
|
3689
|
+
? undefined
|
|
3690
|
+
: lines;
|
|
3453
3691
|
}
|
|
3454
3692
|
}
|
|
3455
3693
|
}
|
|
@@ -3464,6 +3702,21 @@ export function viewToSummary(view) {
|
|
|
3464
3702
|
return truncate(view.command ?? view.output.split('\n')[0] ?? '', 120);
|
|
3465
3703
|
}
|
|
3466
3704
|
}
|
|
3705
|
+
/**
|
|
3706
|
+
* The longest first line a result's summary row shows whole, about three
|
|
3707
|
+
* terminal rows. Longer, the row shows its first 120 characters and the body
|
|
3708
|
+
* keeps the line.
|
|
3709
|
+
*/
|
|
3710
|
+
export const RESULT_SUMMARY_WHOLE_MAX = 300;
|
|
3711
|
+
/** A result's summary row for its first line: whole when short enough, else shortened. */
|
|
3712
|
+
export function resultSummaryLine(line) {
|
|
3713
|
+
const flat = line.replace(/\s+/g, ' ');
|
|
3714
|
+
return flat.length <= RESULT_SUMMARY_WHOLE_MAX ? flat : truncate(line, 120);
|
|
3715
|
+
}
|
|
3716
|
+
/** The summary row says everything `line` does (whitespace aside). */
|
|
3717
|
+
function summarySaysAll(line, summary) {
|
|
3718
|
+
return line === summary || line.replace(/\s+/g, ' ') === summary;
|
|
3719
|
+
}
|
|
3467
3720
|
function truncate(value, max) {
|
|
3468
3721
|
const oneLine = value.replace(/\s+/g, ' ');
|
|
3469
3722
|
return oneLine.length > max ? `${oneLine.slice(0, max - 1)}…` : oneLine;
|
|
@@ -3573,7 +3826,9 @@ function logCapabilities(probes, runtime) {
|
|
|
3573
3826
|
? runtime.sandboxReady
|
|
3574
3827
|
: p.specifier === '@namzu/computer-use'
|
|
3575
3828
|
? runtime.computerUseReady
|
|
3576
|
-
: p.
|
|
3829
|
+
: p.specifier === '@namzu/browser'
|
|
3830
|
+
? runtime.browserReady === true
|
|
3831
|
+
: p.state === 'present';
|
|
3577
3832
|
return `${p.specifier.split('/').pop()} ${present ? 'yes' : 'no'}`;
|
|
3578
3833
|
})
|
|
3579
3834
|
.join(' · ');
|
|
@@ -3597,6 +3852,22 @@ function logCapabilities(probes, runtime) {
|
|
|
3597
3852
|
...(probe.state === 'present' ? { 'namzu.capability.version': probe.version } : {}),
|
|
3598
3853
|
});
|
|
3599
3854
|
}
|
|
3855
|
+
if (runtime.browser) {
|
|
3856
|
+
// The engine and profile the browser tools will use; nothing is running yet.
|
|
3857
|
+
log.info('Browser tools mounted', {
|
|
3858
|
+
[EVENT_NAME_ATTRIBUTE]: BOOT_EVENT_NAMES.CAPABILITY_DETECTED,
|
|
3859
|
+
'namzu.capability.name': '@namzu/browser',
|
|
3860
|
+
'namzu.capability.state': runtime.browserUnavailable === undefined ? 'ready' : 'unavailable',
|
|
3861
|
+
'namzu.capability.present': runtime.browserReady === true,
|
|
3862
|
+
'namzu.browser.engine': runtime.browser.engine,
|
|
3863
|
+
'namzu.browser.profile': runtime.browser.profile,
|
|
3864
|
+
'namzu.browser.headless': runtime.browser.headless,
|
|
3865
|
+
'namzu.browser.site_count': Object.keys(runtime.browser.sites).length,
|
|
3866
|
+
...(runtime.browserUnavailable !== undefined
|
|
3867
|
+
? { 'namzu.browser.unavailable_reason': runtime.browserUnavailable }
|
|
3868
|
+
: {}),
|
|
3869
|
+
});
|
|
3870
|
+
}
|
|
3600
3871
|
if (runtime.computerUseError) {
|
|
3601
3872
|
log.warn('Computer use adapter is unavailable', {
|
|
3602
3873
|
[EVENT_NAME_ATTRIBUTE]: BOOT_EVENT_NAMES.CAPABILITY_DETECTED,
|