hoomanjs 1.46.0 → 1.55.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/README.md +44 -18
- package/dist/acp/acp-agent.d.ts +42 -0
- package/dist/acp/acp-agent.js +336 -47
- package/dist/acp/acp-agent.js.map +1 -1
- package/dist/acp/approvals.js +11 -10
- package/dist/acp/approvals.js.map +1 -1
- package/dist/acp/browser.d.ts +9 -0
- package/dist/acp/browser.js +23 -0
- package/dist/acp/browser.js.map +1 -0
- package/dist/acp/meta/vscode.d.ts +8 -7
- package/dist/acp/meta/vscode.js +10 -11
- package/dist/acp/meta/vscode.js.map +1 -1
- package/dist/acp/session-config.d.ts +2 -2
- package/dist/acp/session-config.js +24 -20
- package/dist/acp/session-config.js.map +1 -1
- package/dist/acp/sessions/store.d.ts +3 -3
- package/dist/acp/utils/tool-kind.js +8 -6
- package/dist/acp/utils/tool-kind.js.map +1 -1
- package/dist/chat/app.js +91 -11
- package/dist/chat/app.js.map +1 -1
- package/dist/chat/approvals.js +3 -0
- package/dist/chat/approvals.js.map +1 -1
- package/dist/chat/components/ApprovalPrompt.js +15 -25
- package/dist/chat/components/ApprovalPrompt.js.map +1 -1
- package/dist/chat/components/BackgroundJobsPanel.d.ts +10 -0
- package/dist/chat/components/BackgroundJobsPanel.js +15 -0
- package/dist/chat/components/BackgroundJobsPanel.js.map +1 -0
- package/dist/chat/components/BottomChrome.d.ts +6 -1
- package/dist/chat/components/BottomChrome.js +3 -2
- package/dist/chat/components/BottomChrome.js.map +1 -1
- package/dist/chat/components/ChromePicker.d.ts +7 -2
- package/dist/chat/components/ChromePicker.js +18 -2
- package/dist/chat/components/ChromePicker.js.map +1 -1
- package/dist/chat/components/Composer.js +3 -2
- package/dist/chat/components/Composer.js.map +1 -1
- package/dist/chat/components/DownloadPanel.js +2 -1
- package/dist/chat/components/DownloadPanel.js.map +1 -1
- package/dist/chat/components/EmptyChatBanner.js +2 -1
- package/dist/chat/components/EmptyChatBanner.js.map +1 -1
- package/dist/chat/components/PromptInput.js +2 -1
- package/dist/chat/components/PromptInput.js.map +1 -1
- package/dist/chat/components/QuestionPrompt.js +5 -4
- package/dist/chat/components/QuestionPrompt.js.map +1 -1
- package/dist/chat/components/QueuedPrompts.js +3 -2
- package/dist/chat/components/QueuedPrompts.js.map +1 -1
- package/dist/chat/components/ReasoningStrip.js +2 -1
- package/dist/chat/components/ReasoningStrip.js.map +1 -1
- package/dist/chat/components/RetryEvent.js +2 -1
- package/dist/chat/components/RetryEvent.js.map +1 -1
- package/dist/chat/components/SelectPicker.js +2 -1
- package/dist/chat/components/SelectPicker.js.map +1 -1
- package/dist/chat/components/ShellToolEvent.d.ts +12 -0
- package/dist/chat/components/ShellToolEvent.js +94 -0
- package/dist/chat/components/ShellToolEvent.js.map +1 -0
- package/dist/chat/components/SlashCommands.js +2 -1
- package/dist/chat/components/SlashCommands.js.map +1 -1
- package/dist/chat/components/Spinner.js +2 -1
- package/dist/chat/components/Spinner.js.map +1 -1
- package/dist/chat/components/StatusBar.js +19 -15
- package/dist/chat/components/StatusBar.js.map +1 -1
- package/dist/chat/components/ThinkingStatus.js +2 -1
- package/dist/chat/components/ThinkingStatus.js.map +1 -1
- package/dist/chat/components/ThoughtEvent.js +2 -1
- package/dist/chat/components/ThoughtEvent.js.map +1 -1
- package/dist/chat/components/TodoPanel.js +2 -1
- package/dist/chat/components/TodoPanel.js.map +1 -1
- package/dist/chat/components/ToolEvent.d.ts +2 -1
- package/dist/chat/components/ToolEvent.js +9 -2
- package/dist/chat/components/ToolEvent.js.map +1 -1
- package/dist/chat/components/ToolEventFileResult.js +8 -7
- package/dist/chat/components/ToolEventFileResult.js.map +1 -1
- package/dist/chat/components/Transcript.d.ts +4 -2
- package/dist/chat/components/Transcript.js +4 -4
- package/dist/chat/components/Transcript.js.map +1 -1
- package/dist/chat/components/markdown/BlockRenderer.js +3 -2
- package/dist/chat/components/markdown/BlockRenderer.js.map +1 -1
- package/dist/chat/components/markdown/CodeBlock.js +3 -2
- package/dist/chat/components/markdown/CodeBlock.js.map +1 -1
- package/dist/chat/components/markdown/InlineRenderer.js +6 -5
- package/dist/chat/components/markdown/InlineRenderer.js.map +1 -1
- package/dist/chat/components/shared.js +7 -6
- package/dist/chat/components/shared.js.map +1 -1
- package/dist/chat/types.d.ts +7 -0
- package/dist/cli.js +162 -44
- package/dist/cli.js.map +1 -1
- package/dist/configure/app.js +46 -29
- package/dist/configure/app.js.map +1 -1
- package/dist/configure/components/BusyScreen.js +2 -1
- package/dist/configure/components/BusyScreen.js.map +1 -1
- package/dist/configure/components/MenuScreen.js +3 -2
- package/dist/configure/components/MenuScreen.js.map +1 -1
- package/dist/configure/components/PromptForm.js +2 -1
- package/dist/configure/components/PromptForm.js.map +1 -1
- package/dist/configure/components/SelectMenuItem.js +4 -3
- package/dist/configure/components/SelectMenuItem.js.map +1 -1
- package/dist/configure/utils.js +4 -3
- package/dist/configure/utils.js.map +1 -1
- package/dist/core/agent/default-retry-strategy.js +46 -12
- package/dist/core/agent/default-retry-strategy.js.map +1 -1
- package/dist/core/agent/gitignore-guard-plugin.js +17 -2
- package/dist/core/agent/gitignore-guard-plugin.js.map +1 -1
- package/dist/core/agent/index.js +38 -7
- package/dist/core/agent/index.js.map +1 -1
- package/dist/core/approvals/allowlist.js +1 -0
- package/dist/core/approvals/allowlist.js.map +1 -1
- package/dist/core/approvals/intervention.d.ts +10 -2
- package/dist/core/approvals/intervention.js +46 -8
- package/dist/core/approvals/intervention.js.map +1 -1
- package/dist/core/config.d.ts +9 -2
- package/dist/core/config.js +8 -4
- package/dist/core/config.js.map +1 -1
- package/dist/core/index.d.ts +2 -2
- package/dist/core/mcp/oauth/service.js +2 -2
- package/dist/core/mcp/oauth/service.js.map +1 -1
- package/dist/core/models/bedrock.js +6 -0
- package/dist/core/models/bedrock.js.map +1 -1
- package/dist/core/models/groq.js +34 -14
- package/dist/core/models/groq.js.map +1 -1
- package/dist/core/models/minimax.js +1 -1
- package/dist/core/models/minimax.js.map +1 -1
- package/dist/core/models/types.d.ts +10 -2
- package/dist/core/models/types.js +1 -0
- package/dist/core/models/types.js.map +1 -1
- package/dist/core/modes/definitions.d.ts +4 -2
- package/dist/core/modes/definitions.js +77 -9
- package/dist/core/modes/definitions.js.map +1 -1
- package/dist/core/modes/index.d.ts +1 -1
- package/dist/core/modes/index.js +1 -1
- package/dist/core/modes/index.js.map +1 -1
- package/dist/core/modes/registry.js +4 -9
- package/dist/core/modes/registry.js.map +1 -1
- package/dist/core/modes/schema.d.ts +1 -1
- package/dist/core/modes/schema.js +1 -1
- package/dist/core/modes/schema.js.map +1 -1
- package/dist/core/prompts/agents/{review.md → code-review.md} +2 -2
- package/dist/core/prompts/agents/design-review.md +35 -0
- package/dist/core/prompts/agents/{test-investigator.md → quality-analyst.md} +2 -2
- package/dist/core/prompts/modes/agent.md +2 -0
- package/dist/core/prompts/modes/ask.md +2 -2
- package/dist/core/prompts/modes/design.md +37 -0
- package/dist/core/prompts/modes/plan.md +5 -5
- package/dist/core/prompts/{runtime.js → runtime/agents.js} +2 -2
- package/dist/core/prompts/runtime/agents.js.map +1 -0
- package/dist/core/prompts/runtime/design.d.ts +11 -0
- package/dist/core/prompts/runtime/design.js +78 -0
- package/dist/core/prompts/runtime/design.js.map +1 -0
- package/dist/core/prompts/{session-mode-appendix.js → session-mode.js} +1 -1
- package/dist/core/prompts/session-mode.js.map +1 -0
- package/dist/core/prompts/static/ask-user.md +3 -2
- package/dist/core/prompts/static/fetch.md +2 -1
- package/dist/core/prompts/static/filesystem.md +2 -1
- package/dist/core/prompts/static/shell.md +21 -1
- package/dist/core/prompts/static/subagents.md +2 -1
- package/dist/core/prompts/static/switch-mode.md +10 -0
- package/dist/core/prompts/system.d.ts +1 -0
- package/dist/core/prompts/system.js +11 -3
- package/dist/core/prompts/system.js.map +1 -1
- package/dist/core/shell/index.d.ts +7 -0
- package/dist/core/shell/index.js +6 -0
- package/dist/core/shell/index.js.map +1 -0
- package/dist/core/shell/manager.d.ts +23 -0
- package/dist/core/shell/manager.js +604 -0
- package/dist/core/shell/manager.js.map +1 -0
- package/dist/core/shell/output-buffer.d.ts +30 -0
- package/dist/core/shell/output-buffer.js +116 -0
- package/dist/core/shell/output-buffer.js.map +1 -0
- package/dist/core/shell/registry.d.ts +5 -0
- package/dist/core/shell/registry.js +24 -0
- package/dist/core/shell/registry.js.map +1 -0
- package/dist/core/{tools/shell.d.ts → shell/terminal-backend.d.ts} +20 -18
- package/dist/core/shell/terminal-backend.js +18 -0
- package/dist/core/shell/terminal-backend.js.map +1 -0
- package/dist/core/shell/tools.d.ts +41 -0
- package/dist/core/{tools/shell.js → shell/tools.js} +186 -11
- package/dist/core/shell/tools.js.map +1 -0
- package/dist/core/shell/types.d.ts +95 -0
- package/dist/core/shell/types.js +2 -0
- package/dist/core/shell/types.js.map +1 -0
- package/dist/core/skills/built-in/hooman-config/SKILL.md +30 -35
- package/dist/core/skills/built-in/hooman-config/search.md +5 -3
- package/dist/core/skills/built-in/hooman-design/SKILL.md +97 -0
- package/dist/core/skills/built-in/hooman-design/assets/article-shell.html +87 -0
- package/dist/core/skills/built-in/hooman-design/assets/auth-shell.html +143 -0
- package/dist/core/skills/built-in/hooman-design/assets/business-card-shell.html +112 -0
- package/dist/core/skills/built-in/hooman-design/assets/contact-shell.html +181 -0
- package/dist/core/skills/built-in/hooman-design/assets/dashboard-shell.html +90 -0
- package/dist/core/skills/built-in/hooman-design/assets/data-table-shell.html +114 -0
- package/dist/core/skills/built-in/hooman-design/assets/deck-shell.html +187 -0
- package/dist/core/skills/built-in/hooman-design/assets/dialog-shell.html +98 -0
- package/dist/core/skills/built-in/hooman-design/assets/email-shell.html +101 -0
- package/dist/core/skills/built-in/hooman-design/assets/empty-state-shell.html +92 -0
- package/dist/core/skills/built-in/hooman-design/assets/flyer-shell.html +168 -0
- package/dist/core/skills/built-in/hooman-design/assets/invite-shell.html +167 -0
- package/dist/core/skills/built-in/hooman-design/assets/landing-shell.html +184 -0
- package/dist/core/skills/built-in/hooman-design/assets/mobile-frame-shell.html +109 -0
- package/dist/core/skills/built-in/hooman-design/assets/newsletter-shell.html +141 -0
- package/dist/core/skills/built-in/hooman-design/assets/onboarding-shell.html +131 -0
- package/dist/core/skills/built-in/hooman-design/assets/pricing-shell.html +160 -0
- package/dist/core/skills/built-in/hooman-design/assets/prototype-shell.html +83 -0
- package/dist/core/skills/built-in/hooman-design/assets/resume-shell.html +228 -0
- package/dist/core/skills/built-in/hooman-design/assets/settings-shell.html +196 -0
- package/dist/core/skills/built-in/hooman-design/assets/tokens/botanical-calm.css +34 -0
- package/dist/core/skills/built-in/hooman-design/assets/tokens/copper-ledger.css +34 -0
- package/dist/core/skills/built-in/hooman-design/assets/tokens/editorial-ink.css +34 -0
- package/dist/core/skills/built-in/hooman-design/assets/tokens/fintech-clear.css +34 -0
- package/dist/core/skills/built-in/hooman-design/assets/tokens/harbor-navy.css +35 -0
- package/dist/core/skills/built-in/hooman-design/assets/tokens/midnight-editorial.css +34 -0
- package/dist/core/skills/built-in/hooman-design/assets/tokens/night-console.css +34 -0
- package/dist/core/skills/built-in/hooman-design/assets/tokens/paper-mono.css +35 -0
- package/dist/core/skills/built-in/hooman-design/assets/tokens/signal-mono.css +34 -0
- package/dist/core/skills/built-in/hooman-design/assets/tokens/soft-product.css +34 -0
- package/dist/core/skills/built-in/hooman-design/assets/tokens/swiss-grid.css +34 -0
- package/dist/core/skills/built-in/hooman-design/assets/tokens/warm-atelier.css +34 -0
- package/dist/core/skills/built-in/hooman-design/assets/waitlist-shell.html +139 -0
- package/dist/core/skills/built-in/hooman-design/craft/accessibility-baseline.md +32 -0
- package/dist/core/skills/built-in/hooman-design/craft/anti-ai-slop.md +27 -0
- package/dist/core/skills/built-in/hooman-design/craft/color-surfaces.md +45 -0
- package/dist/core/skills/built-in/hooman-design/craft/data-viz.md +24 -0
- package/dist/core/skills/built-in/hooman-design/craft/deck-slides.md +46 -0
- package/dist/core/skills/built-in/hooman-design/craft/forms-validation.md +35 -0
- package/dist/core/skills/built-in/hooman-design/craft/iconography.md +19 -0
- package/dist/core/skills/built-in/hooman-design/craft/layout-overflow.md +31 -0
- package/dist/core/skills/built-in/hooman-design/craft/motion.md +41 -0
- package/dist/core/skills/built-in/hooman-design/craft/print.md +37 -0
- package/dist/core/skills/built-in/hooman-design/craft/responsive.md +30 -0
- package/dist/core/skills/built-in/hooman-design/craft/spacing-density.md +46 -0
- package/dist/core/skills/built-in/hooman-design/craft/state-coverage.md +21 -0
- package/dist/core/skills/built-in/hooman-design/craft/typography.md +73 -0
- package/dist/core/skills/built-in/hooman-design/directions.md +115 -0
- package/dist/core/skills/built-in/hooman-design/references/artifact-layout.md +15 -0
- package/dist/core/skills/built-in/hooman-design/references/export.md +47 -0
- package/dist/core/skills/built-in/hooman-design/references/workflow.md +80 -0
- package/dist/core/skills/built-in/hooman-mcp/SKILL.md +2 -2
- package/dist/core/state/llm-modality.d.ts +13 -0
- package/dist/core/state/llm-modality.js +19 -0
- package/dist/core/state/llm-modality.js.map +1 -0
- package/dist/core/state/plan.d.ts +1 -1
- package/dist/core/state/plan.js +1 -1
- package/dist/core/state/shell-jobs.d.ts +9 -0
- package/dist/core/state/shell-jobs.js +20 -0
- package/dist/core/state/shell-jobs.js.map +1 -0
- package/dist/core/state/tool-approvals.d.ts +12 -9
- package/dist/core/state/tool-approvals.js +94 -52
- package/dist/core/state/tool-approvals.js.map +1 -1
- package/dist/core/state/turn-boundaries.d.ts +33 -0
- package/dist/core/state/turn-boundaries.js +49 -0
- package/dist/core/state/turn-boundaries.js.map +1 -0
- package/dist/core/subagents/index.d.ts +1 -1
- package/dist/core/subagents/index.js +1 -1
- package/dist/core/subagents/registry.js +15 -6
- package/dist/core/subagents/registry.js.map +1 -1
- package/dist/core/subagents/tool.d.ts +8 -2
- package/dist/core/subagents/tool.js +93 -44
- package/dist/core/subagents/tool.js.map +1 -1
- package/dist/core/theme.d.ts +14 -0
- package/dist/core/theme.js +14 -0
- package/dist/core/theme.js.map +1 -0
- package/dist/core/tools/ask-user.d.ts +1 -1
- package/dist/core/tools/ask-user.js +1 -1
- package/dist/core/tools/export.d.ts +8 -0
- package/dist/core/tools/export.js +202 -0
- package/dist/core/tools/export.js.map +1 -0
- package/dist/core/tools/fetch.d.ts +2 -0
- package/dist/core/tools/fetch.js +92 -55
- package/dist/core/tools/fetch.js.map +1 -1
- package/dist/core/tools/filesystem.d.ts +2 -1
- package/dist/core/tools/filesystem.js +38 -4
- package/dist/core/tools/filesystem.js.map +1 -1
- package/dist/core/tools/index.d.ts +3 -2
- package/dist/core/tools/index.js +3 -2
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/preview.d.ts +10 -0
- package/dist/core/tools/preview.js +147 -0
- package/dist/core/tools/preview.js.map +1 -0
- package/dist/core/tools/switch-mode.d.ts +6 -0
- package/dist/core/tools/switch-mode.js +188 -0
- package/dist/core/tools/switch-mode.js.map +1 -0
- package/dist/core/tools/web-search.js +176 -0
- package/dist/core/tools/web-search.js.map +1 -1
- package/dist/core/utils/browser.d.ts +8 -1
- package/dist/core/utils/browser.js +17 -1
- package/dist/core/utils/browser.js.map +1 -1
- package/dist/core/utils/export-design.d.ts +40 -0
- package/dist/core/utils/export-design.js +188 -0
- package/dist/core/utils/export-design.js.map +1 -0
- package/dist/core/utils/export-figma.d.ts +17 -0
- package/dist/core/utils/export-figma.js +189 -0
- package/dist/core/utils/export-figma.js.map +1 -0
- package/dist/core/utils/export-sketch.d.ts +11 -0
- package/dist/core/utils/export-sketch.js +456 -0
- package/dist/core/utils/export-sketch.js.map +1 -0
- package/dist/core/utils/fig-archive.d.ts +47 -0
- package/dist/core/utils/fig-archive.js +181 -0
- package/dist/core/utils/fig-archive.js.map +1 -0
- package/dist/core/utils/metadata.d.ts +30 -0
- package/dist/core/utils/metadata.js +122 -0
- package/dist/core/utils/metadata.js.map +1 -1
- package/dist/core/utils/models-prefetch.d.ts +53 -0
- package/dist/core/utils/models-prefetch.js +469 -0
- package/dist/core/utils/models-prefetch.js.map +1 -0
- package/dist/core/utils/onboarding-config.d.ts +48 -0
- package/dist/core/utils/onboarding-config.js +373 -0
- package/dist/core/utils/onboarding-config.js.map +1 -0
- package/dist/core/utils/paths.d.ts +9 -7
- package/dist/core/utils/paths.js +12 -10
- package/dist/core/utils/paths.js.map +1 -1
- package/dist/core/utils/preview-server.d.ts +20 -0
- package/dist/core/utils/preview-server.js +212 -0
- package/dist/core/utils/preview-server.js.map +1 -0
- package/dist/core/utils/search-probe.d.ts +19 -0
- package/dist/core/utils/search-probe.js +165 -0
- package/dist/core/utils/search-probe.js.map +1 -0
- package/dist/core/utils/seeds/empty-slides.deck +0 -0
- package/dist/core/utils/url-safety.d.ts +2 -0
- package/dist/core/utils/url-safety.js +47 -0
- package/dist/core/utils/url-safety.js.map +1 -0
- package/dist/core/utils/zstd.d.ts +6 -0
- package/dist/core/utils/zstd.js +39 -0
- package/dist/core/utils/zstd.js.map +1 -0
- package/dist/exec/approvals.js +5 -5
- package/dist/exec/approvals.js.map +1 -1
- package/dist/index.d.ts +11 -5
- package/dist/index.js +8 -5
- package/dist/index.js.map +1 -1
- package/dist/onboarding/app.d.ts +5 -0
- package/dist/onboarding/app.js +255 -0
- package/dist/onboarding/app.js.map +1 -0
- package/dist/onboarding/index.d.ts +5 -0
- package/dist/onboarding/index.js +27 -0
- package/dist/onboarding/index.js.map +1 -0
- package/package.json +16 -3
- package/dist/core/prompts/runtime.js.map +0 -1
- package/dist/core/prompts/session-mode-appendix.js.map +0 -1
- package/dist/core/prompts/static/planning.md +0 -3
- package/dist/core/tools/plan.d.ts +0 -5
- package/dist/core/tools/plan.js +0 -150
- package/dist/core/tools/plan.js.map +0 -1
- package/dist/core/tools/shell.js.map +0 -1
- /package/dist/core/prompts/{runtime.d.ts → runtime/agents.d.ts} +0 -0
- /package/dist/core/prompts/{session-mode-appendix.d.ts → session-mode.d.ts} +0 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared brand palette for CLI Ink surfaces (and any other non-webview UI).
|
|
3
|
+
* VS Code webviews mirror these values in `src/vscode/webview/index.css`.
|
|
4
|
+
*/
|
|
5
|
+
export const theme = {
|
|
6
|
+
primary: "#0091cd",
|
|
7
|
+
secondary: "#56a0d3",
|
|
8
|
+
warning: "#ecb731",
|
|
9
|
+
error: "#ee4c58",
|
|
10
|
+
success: "#8ec06c",
|
|
11
|
+
info: "#c4dff6",
|
|
12
|
+
muted: "#9ba5a8",
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=theme.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.js","sourceRoot":"","sources":["../../src/core/theme.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,OAAO,EAAE,SAAS;IAClB,SAAS,EAAE,SAAS;IACpB,OAAO,EAAE,SAAS;IAClB,KAAK,EAAE,SAAS;IAChB,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,SAAS;IACf,KAAK,EAAE,SAAS;CACR,CAAC"}
|
|
@@ -13,7 +13,7 @@ export declare const ASK_USER_TOOL_NAME = "ask_user";
|
|
|
13
13
|
export type AskUserRequest = {
|
|
14
14
|
/** The question to present to the user. */
|
|
15
15
|
question: string;
|
|
16
|
-
/** 2–
|
|
16
|
+
/** 2–6 answer choices, in display order. */
|
|
17
17
|
options: string[];
|
|
18
18
|
/** Tool-use id of the `ask_user` call, for frontends that key UI on it. */
|
|
19
19
|
toolUseId?: string;
|
|
@@ -2,7 +2,7 @@ import { tool } from "@strands-agents/sdk";
|
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
export const ASK_USER_TOOL_NAME = "ask_user";
|
|
4
4
|
const MIN_OPTIONS = 2;
|
|
5
|
-
const MAX_OPTIONS =
|
|
5
|
+
const MAX_OPTIONS = 6;
|
|
6
6
|
/** Keyed by the Strands agent instance so backends are never serialized. */
|
|
7
7
|
const backends = new WeakMap();
|
|
8
8
|
export function setAskUserBackend(agent, backend) {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { JSONValue } from "@strands-agents/sdk";
|
|
2
|
+
export declare const EXPORT_DESIGN_TOOL_NAME = "export_design";
|
|
3
|
+
export declare function createExportTools(): import("@strands-agents/sdk").InvokableTool<{
|
|
4
|
+
path: string;
|
|
5
|
+
format: "pdf" | "pptx" | "sketch" | "images-to-pdf" | "images" | "figma" | "figma-deck";
|
|
6
|
+
out?: string | undefined;
|
|
7
|
+
title?: string | undefined;
|
|
8
|
+
}, JSONValue>[];
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname, isAbsolute, join } from "node:path";
|
|
3
|
+
import { tool } from "@strands-agents/sdk";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { getCwd } from "../utils/cwd-context.js";
|
|
6
|
+
import { buildScreenshotDeck, buildScreenshotFig, buildScreenshotPdf, buildScreenshotPptx, buildScreenshotSketch, defaultExportPath, renderHtmlToImages, renderHtmlToPdfBuffer, } from "../utils/export-design.js";
|
|
7
|
+
import { isResolvedPathInsideDir, normalizeUserPath, } from "../utils/normalize-user-path.js";
|
|
8
|
+
export const EXPORT_DESIGN_TOOL_NAME = "export_design";
|
|
9
|
+
const EXPORT_FORMATS = [
|
|
10
|
+
"pdf",
|
|
11
|
+
"images-to-pdf",
|
|
12
|
+
"images",
|
|
13
|
+
"pptx",
|
|
14
|
+
"figma",
|
|
15
|
+
"figma-deck",
|
|
16
|
+
"sketch",
|
|
17
|
+
];
|
|
18
|
+
const DELIVERY_FORMATS = "pdf / images-to-pdf / pptx / figma / figma-deck / sketch";
|
|
19
|
+
function toJsonValue(value) {
|
|
20
|
+
return JSON.parse(JSON.stringify(value));
|
|
21
|
+
}
|
|
22
|
+
function resolveHtml(raw) {
|
|
23
|
+
const cwd = getCwd();
|
|
24
|
+
const resolved = isAbsolute(raw.trim())
|
|
25
|
+
? raw.trim()
|
|
26
|
+
: normalizeUserPath(raw.trim());
|
|
27
|
+
if (!isResolvedPathInsideDir(resolved, cwd)) {
|
|
28
|
+
throw new Error(`HTML path must stay under the session working directory (${cwd}).`);
|
|
29
|
+
}
|
|
30
|
+
return resolved;
|
|
31
|
+
}
|
|
32
|
+
function resolveOutPath(htmlPath, out, format) {
|
|
33
|
+
const cwd = getCwd();
|
|
34
|
+
if (out?.trim()) {
|
|
35
|
+
const target = isAbsolute(out.trim())
|
|
36
|
+
? out.trim()
|
|
37
|
+
: normalizeUserPath(out.trim());
|
|
38
|
+
if (!isResolvedPathInsideDir(target, cwd)) {
|
|
39
|
+
throw new Error(`Output path must stay under the session working directory (${cwd}).`);
|
|
40
|
+
}
|
|
41
|
+
return target;
|
|
42
|
+
}
|
|
43
|
+
if (format === "images") {
|
|
44
|
+
// Visual QA default: reviews/ next to the HTML entry.
|
|
45
|
+
return join(dirname(htmlPath), "reviews");
|
|
46
|
+
}
|
|
47
|
+
const ext = format === "pptx"
|
|
48
|
+
? "pptx"
|
|
49
|
+
: format === "figma"
|
|
50
|
+
? "fig"
|
|
51
|
+
: format === "figma-deck"
|
|
52
|
+
? "deck"
|
|
53
|
+
: format === "sketch"
|
|
54
|
+
? "sketch"
|
|
55
|
+
: "pdf";
|
|
56
|
+
const target = defaultExportPath(htmlPath, ext);
|
|
57
|
+
if (!isResolvedPathInsideDir(target, cwd)) {
|
|
58
|
+
throw new Error(`Output path must stay under the session working directory (${cwd}).`);
|
|
59
|
+
}
|
|
60
|
+
return target;
|
|
61
|
+
}
|
|
62
|
+
function playwrightHint(message) {
|
|
63
|
+
if (/Executable doesn't exist|browserType\.launch/i.test(message)) {
|
|
64
|
+
return `${message} Install Chromium with: npx playwright install chromium`;
|
|
65
|
+
}
|
|
66
|
+
return message;
|
|
67
|
+
}
|
|
68
|
+
function imageFileName(index, total, jpeg) {
|
|
69
|
+
const ext = jpeg ? "jpg" : "png";
|
|
70
|
+
if (total <= 1) {
|
|
71
|
+
return `shot-01.${ext}`;
|
|
72
|
+
}
|
|
73
|
+
return `slide-${String(index + 1).padStart(2, "0")}.${ext}`;
|
|
74
|
+
}
|
|
75
|
+
async function writeImagePages(outDir, images) {
|
|
76
|
+
await mkdir(outDir, { recursive: true });
|
|
77
|
+
const written = [];
|
|
78
|
+
for (let i = 0; i < images.length; i++) {
|
|
79
|
+
const img = images[i];
|
|
80
|
+
if (!img) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
const filePath = join(outDir, imageFileName(i, images.length, img.jpeg));
|
|
84
|
+
await writeFile(filePath, img.buffer);
|
|
85
|
+
written.push(filePath);
|
|
86
|
+
}
|
|
87
|
+
return written;
|
|
88
|
+
}
|
|
89
|
+
export function createExportTools() {
|
|
90
|
+
return [
|
|
91
|
+
tool({
|
|
92
|
+
name: EXPORT_DESIGN_TOOL_NAME,
|
|
93
|
+
description: `Export or capture an HTML design artifact. Formats: images (screenshots under reviews/ by default — use for visual QA, then call launch_subagent with kind design-review, every returned path, and binary:true reads), pdf (Chromium print), images-to-pdf (pages → PDF), pptx (PowerPoint-ready .pptx), figma / figma-deck / sketch (Figma-ready .fig / .deck or Sketch-ready .sketch). Delivery formats (${DELIVERY_FORMATS}) only after visual QA (images + launch_subagent kind design-review, Must-fix empty or round cap reached).`,
|
|
94
|
+
inputSchema: z.object({
|
|
95
|
+
path: z
|
|
96
|
+
.string()
|
|
97
|
+
.min(1)
|
|
98
|
+
.describe("Path to the HTML entry file (usually index.html)."),
|
|
99
|
+
format: z
|
|
100
|
+
.enum(EXPORT_FORMATS)
|
|
101
|
+
.describe("images = page screenshots (visual QA); pdf = Chromium print; images-to-pdf = pages → PDF; pptx = PowerPoint-ready .pptx; figma / figma-deck = Figma-ready .fig / .deck; sketch = Sketch-ready .sketch."),
|
|
102
|
+
out: z
|
|
103
|
+
.string()
|
|
104
|
+
.optional()
|
|
105
|
+
.describe("Optional output path under the session cwd (.pdf / .pptx / .fig / .deck / .sketch file, or directory for images; images default to <html-dir>/reviews)."),
|
|
106
|
+
title: z
|
|
107
|
+
.string()
|
|
108
|
+
.optional()
|
|
109
|
+
.describe("Optional presentation title (pptx / figma / figma-deck / sketch)."),
|
|
110
|
+
}),
|
|
111
|
+
callback: async (input) => {
|
|
112
|
+
try {
|
|
113
|
+
const htmlPath = resolveHtml(input.path);
|
|
114
|
+
const outPath = resolveOutPath(htmlPath, input.out, input.format);
|
|
115
|
+
if (input.format === "pdf") {
|
|
116
|
+
await mkdir(dirname(outPath), { recursive: true });
|
|
117
|
+
const buffer = await renderHtmlToPdfBuffer(htmlPath);
|
|
118
|
+
await writeFile(outPath, buffer);
|
|
119
|
+
return toJsonValue({
|
|
120
|
+
status: "ok",
|
|
121
|
+
format: input.format,
|
|
122
|
+
path: outPath,
|
|
123
|
+
bytes: buffer.byteLength,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
if (input.format === "images-to-pdf") {
|
|
127
|
+
await mkdir(dirname(outPath), { recursive: true });
|
|
128
|
+
const images = await renderHtmlToImages({
|
|
129
|
+
path: htmlPath,
|
|
130
|
+
format: "png",
|
|
131
|
+
});
|
|
132
|
+
const buffer = await buildScreenshotPdf(images);
|
|
133
|
+
await writeFile(outPath, buffer);
|
|
134
|
+
return toJsonValue({
|
|
135
|
+
status: "ok",
|
|
136
|
+
format: input.format,
|
|
137
|
+
path: outPath,
|
|
138
|
+
bytes: buffer.byteLength,
|
|
139
|
+
pages: images.length,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
if (input.format === "images") {
|
|
143
|
+
const images = await renderHtmlToImages({
|
|
144
|
+
path: htmlPath,
|
|
145
|
+
format: "png",
|
|
146
|
+
});
|
|
147
|
+
const pages = await writeImagePages(outPath, images);
|
|
148
|
+
return toJsonValue({
|
|
149
|
+
status: "ok",
|
|
150
|
+
format: input.format,
|
|
151
|
+
path: outPath,
|
|
152
|
+
pages,
|
|
153
|
+
nextTool: "launch_subagent",
|
|
154
|
+
nextKind: "design-review",
|
|
155
|
+
nextQueryTemplate: `Visually review this design artifact. Entry: ${htmlPath}. Read EVERY screenshot below with read_file binary:true before judging layout. Flag overflow, overlap, clipping, cramped cards, and footer/chrome collisions as Must-fix.\n\nScreenshots:\n${pages.map((p) => `- ${p}`).join("\n")}`,
|
|
156
|
+
hint: `Capture is not review. Your next tool call must be launch_subagent with kind design-review using nextQueryTemplate (or equivalent). Do not export_design with ${DELIVERY_FORMATS} or mark work complete until that review returns and Must-fix are addressed.`,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
if (input.format === "figma" ||
|
|
160
|
+
input.format === "figma-deck" ||
|
|
161
|
+
input.format === "sketch" ||
|
|
162
|
+
input.format === "pptx") {
|
|
163
|
+
await mkdir(dirname(outPath), { recursive: true });
|
|
164
|
+
const images = await renderHtmlToImages({
|
|
165
|
+
path: htmlPath,
|
|
166
|
+
format: "png",
|
|
167
|
+
});
|
|
168
|
+
const buffer = input.format === "figma"
|
|
169
|
+
? await buildScreenshotFig(images, { title: input.title })
|
|
170
|
+
: input.format === "figma-deck"
|
|
171
|
+
? await buildScreenshotDeck(images, { title: input.title })
|
|
172
|
+
: input.format === "sketch"
|
|
173
|
+
? buildScreenshotSketch(images, { title: input.title })
|
|
174
|
+
: await buildScreenshotPptx(images, {
|
|
175
|
+
title: input.title,
|
|
176
|
+
});
|
|
177
|
+
await writeFile(outPath, buffer);
|
|
178
|
+
return toJsonValue({
|
|
179
|
+
status: "ok",
|
|
180
|
+
format: input.format,
|
|
181
|
+
path: outPath,
|
|
182
|
+
bytes: buffer.byteLength,
|
|
183
|
+
slides: images.length,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
return toJsonValue({
|
|
187
|
+
status: "error",
|
|
188
|
+
message: `Unsupported format: ${String(input.format)}`,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
193
|
+
return toJsonValue({
|
|
194
|
+
status: "error",
|
|
195
|
+
message: playwrightHint(message),
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
}),
|
|
200
|
+
];
|
|
201
|
+
}
|
|
202
|
+
//# sourceMappingURL=export.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export.js","sourceRoot":"","sources":["../../../src/core/tools/export.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { JSONValue } from "@strands-agents/sdk";
|
|
2
2
|
export declare function createFetchTools(): import("@strands-agents/sdk").InvokableTool<{
|
|
3
3
|
url: string;
|
|
4
|
+
save_as?: string | undefined;
|
|
4
5
|
max_length?: number | undefined;
|
|
5
6
|
start_index?: number | undefined;
|
|
6
7
|
raw?: boolean | undefined;
|
|
7
8
|
timeout?: number | undefined;
|
|
9
|
+
max_bytes?: number | undefined;
|
|
8
10
|
headers?: Record<string, string> | undefined;
|
|
9
11
|
}, JSONValue>[];
|
package/dist/core/tools/fetch.js
CHANGED
|
@@ -1,19 +1,26 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
1
|
+
import { createWriteStream } from "node:fs";
|
|
2
|
+
import { mkdir, readFile, unlink } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { Readable } from "node:stream";
|
|
5
|
+
import { pipeline } from "node:stream/promises";
|
|
4
6
|
import { Readability } from "@mozilla/readability";
|
|
5
7
|
import { JSDOM } from "jsdom";
|
|
6
8
|
import { tool } from "@strands-agents/sdk";
|
|
7
9
|
import TurndownService from "turndown";
|
|
8
10
|
import { z } from "zod";
|
|
11
|
+
import { normalizeUserPath } from "../utils/normalize-user-path.js";
|
|
12
|
+
import { assertRemoteUrl, isHttpUrl } from "../utils/url-safety.js";
|
|
9
13
|
async function createUserAgent() {
|
|
10
14
|
const packageUrl = new URL("../../../package.json", import.meta.url);
|
|
11
15
|
const pkg = JSON.parse(await readFile(packageUrl, "utf8"));
|
|
12
16
|
return `${pkg.name ?? "hoomanjs"}/${pkg.version ?? "0.0.0"}`;
|
|
13
17
|
}
|
|
14
18
|
const DEFAULT_TIMEOUT_SECONDS = 30;
|
|
19
|
+
const DEFAULT_DOWNLOAD_TIMEOUT_SECONDS = 60;
|
|
15
20
|
const DEFAULT_MAX_LENGTH = 5000;
|
|
16
21
|
const MAX_FETCH_LENGTH = 1_000_000;
|
|
22
|
+
const DEFAULT_MAX_BYTES = 100 * 1024 * 1024;
|
|
23
|
+
const MAX_DOWNLOAD_BYTES = 1024 * 1024 * 1024;
|
|
17
24
|
const turndown = new TurndownService({
|
|
18
25
|
headingStyle: "atx",
|
|
19
26
|
bulletListMarker: "-",
|
|
@@ -22,50 +29,6 @@ const turndown = new TurndownService({
|
|
|
22
29
|
function toJsonValue(value) {
|
|
23
30
|
return JSON.parse(JSON.stringify(value));
|
|
24
31
|
}
|
|
25
|
-
function isHttpUrl(value) {
|
|
26
|
-
const url = new URL(value);
|
|
27
|
-
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
28
|
-
throw new Error("Only http:// and https:// URLs are supported.");
|
|
29
|
-
}
|
|
30
|
-
return url;
|
|
31
|
-
}
|
|
32
|
-
function isPrivateHostname(hostname) {
|
|
33
|
-
const normalized = hostname.toLowerCase();
|
|
34
|
-
return (normalized === "localhost" ||
|
|
35
|
-
normalized === "127.0.0.1" ||
|
|
36
|
-
normalized === "::1" ||
|
|
37
|
-
normalized.endsWith(".localhost"));
|
|
38
|
-
}
|
|
39
|
-
function isPrivateIp(address) {
|
|
40
|
-
const version = net.isIP(address);
|
|
41
|
-
if (version === 4) {
|
|
42
|
-
const parts = address.split(".").map((part) => Number(part));
|
|
43
|
-
const a = parts[0] ?? -1;
|
|
44
|
-
const b = parts[1] ?? -1;
|
|
45
|
-
return (a === 10 ||
|
|
46
|
-
a === 127 ||
|
|
47
|
-
(a === 172 && b >= 16 && b <= 31) ||
|
|
48
|
-
(a === 192 && b === 168) ||
|
|
49
|
-
(a === 169 && b === 254));
|
|
50
|
-
}
|
|
51
|
-
if (version === 6) {
|
|
52
|
-
const normalized = address.toLowerCase();
|
|
53
|
-
return (normalized === "::1" ||
|
|
54
|
-
normalized.startsWith("fc") ||
|
|
55
|
-
normalized.startsWith("fd") ||
|
|
56
|
-
normalized.startsWith("fe80:"));
|
|
57
|
-
}
|
|
58
|
-
return false;
|
|
59
|
-
}
|
|
60
|
-
async function assertRemoteUrl(url) {
|
|
61
|
-
if (isPrivateHostname(url.hostname)) {
|
|
62
|
-
throw new Error("Fetching localhost or loopback URLs is not allowed.");
|
|
63
|
-
}
|
|
64
|
-
const resolved = await dns.lookup(url.hostname, { all: true });
|
|
65
|
-
if (resolved.some((entry) => isPrivateIp(entry.address))) {
|
|
66
|
-
throw new Error("Fetching private-network URLs is not allowed.");
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
32
|
function responseHeaders(headers) {
|
|
70
33
|
const out = {};
|
|
71
34
|
headers.forEach((value, key) => {
|
|
@@ -120,43 +83,95 @@ function sliceContent(content, startIndex, maxLength) {
|
|
|
120
83
|
function createFetchInputSchema() {
|
|
121
84
|
return z.object({
|
|
122
85
|
url: z.string().url().describe("Remote HTTP(S) URL to fetch."),
|
|
86
|
+
save_as: z
|
|
87
|
+
.string()
|
|
88
|
+
.min(1)
|
|
89
|
+
.optional()
|
|
90
|
+
.describe("When set, stream the response body to this local filesystem path instead of returning content text."),
|
|
123
91
|
max_length: z.coerce
|
|
124
92
|
.number()
|
|
125
93
|
.int()
|
|
126
94
|
.min(1)
|
|
127
95
|
.max(MAX_FETCH_LENGTH)
|
|
128
96
|
.optional()
|
|
129
|
-
.describe("Maximum number of characters to return."),
|
|
97
|
+
.describe("Maximum number of characters to return (ignored when save_as is set)."),
|
|
130
98
|
start_index: z.coerce
|
|
131
99
|
.number()
|
|
132
100
|
.int()
|
|
133
101
|
.min(0)
|
|
134
102
|
.optional()
|
|
135
|
-
.describe("Start returning content from this character index."),
|
|
103
|
+
.describe("Start returning content from this character index (ignored when save_as is set)."),
|
|
136
104
|
raw: z
|
|
137
105
|
.boolean()
|
|
138
106
|
.optional()
|
|
139
|
-
.describe("Return raw response text instead of simplifying HTML to markdown."),
|
|
107
|
+
.describe("Return raw response text instead of simplifying HTML to markdown (ignored when save_as is set)."),
|
|
140
108
|
timeout: z.coerce
|
|
141
109
|
.number()
|
|
142
110
|
.positive()
|
|
143
111
|
.optional()
|
|
144
112
|
.describe("Request timeout in seconds."),
|
|
113
|
+
max_bytes: z.coerce
|
|
114
|
+
.number()
|
|
115
|
+
.int()
|
|
116
|
+
.min(1)
|
|
117
|
+
.max(MAX_DOWNLOAD_BYTES)
|
|
118
|
+
.optional()
|
|
119
|
+
.describe("Maximum number of bytes to write when save_as is set (default 100 MiB)."),
|
|
145
120
|
headers: z
|
|
146
121
|
.record(z.string(), z.string())
|
|
147
122
|
.optional()
|
|
148
123
|
.describe("Optional extra HTTP headers."),
|
|
149
124
|
});
|
|
150
125
|
}
|
|
126
|
+
async function saveResponseToPath(options) {
|
|
127
|
+
const { url, response, filePath, maxBytes } = options;
|
|
128
|
+
if (!response.body) {
|
|
129
|
+
throw new Error(`Empty response body: GET ${url.toString()}`);
|
|
130
|
+
}
|
|
131
|
+
const contentLength = response.headers.get("content-length");
|
|
132
|
+
if (contentLength) {
|
|
133
|
+
const declared = Number(contentLength);
|
|
134
|
+
if (Number.isFinite(declared) && declared > maxBytes) {
|
|
135
|
+
throw new Error(`Remote content-length (${declared} bytes) exceeds max_bytes (${maxBytes}).`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
await mkdir(path.dirname(filePath), { recursive: true });
|
|
139
|
+
let bytesWritten = 0;
|
|
140
|
+
let wroteFile = false;
|
|
141
|
+
try {
|
|
142
|
+
const nodeStream = Readable.fromWeb(response.body);
|
|
143
|
+
nodeStream.on("data", (chunk) => {
|
|
144
|
+
bytesWritten +=
|
|
145
|
+
typeof chunk === "string" ? Buffer.byteLength(chunk) : chunk.byteLength;
|
|
146
|
+
if (bytesWritten > maxBytes) {
|
|
147
|
+
nodeStream.destroy(new Error(`Download exceeded max_bytes (${maxBytes}) after ${bytesWritten} bytes.`));
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
await pipeline(nodeStream, createWriteStream(filePath));
|
|
151
|
+
wroteFile = true;
|
|
152
|
+
return {
|
|
153
|
+
bytesWritten,
|
|
154
|
+
contentType: response.headers.get("content-type") ?? "",
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
if (wroteFile || bytesWritten > 0) {
|
|
159
|
+
await unlink(filePath).catch(() => undefined);
|
|
160
|
+
}
|
|
161
|
+
throw error;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
151
164
|
export function createFetchTools() {
|
|
152
165
|
const inputSchema = createFetchInputSchema();
|
|
153
166
|
return [
|
|
154
167
|
tool({
|
|
155
168
|
name: "fetch",
|
|
156
|
-
description: "Fetch a remote URL and return response content. HTML pages are simplified to markdown by default to save context window and tokens.",
|
|
169
|
+
description: "Fetch a remote URL and return response content, or save the response body to a local path with save_as. HTML pages are simplified to markdown by default to save context window and tokens.",
|
|
157
170
|
inputSchema,
|
|
158
171
|
callback: async (input, context) => {
|
|
159
|
-
const
|
|
172
|
+
const saveAs = input.save_as?.trim();
|
|
173
|
+
const timeoutSeconds = input.timeout ??
|
|
174
|
+
(saveAs ? DEFAULT_DOWNLOAD_TIMEOUT_SECONDS : DEFAULT_TIMEOUT_SECONDS);
|
|
160
175
|
const timeoutSignal = AbortSignal.timeout(timeoutSeconds * 1000);
|
|
161
176
|
const signal = context
|
|
162
177
|
? AbortSignal.any([timeoutSignal, context.agent.cancelSignal])
|
|
@@ -168,7 +183,9 @@ export function createFetchTools() {
|
|
|
168
183
|
headers.set("user-agent", await createUserAgent());
|
|
169
184
|
}
|
|
170
185
|
if (!headers.has("accept")) {
|
|
171
|
-
headers.set("accept",
|
|
186
|
+
headers.set("accept", saveAs
|
|
187
|
+
? "*/*"
|
|
188
|
+
: "text/html,application/xhtml+xml,application/json,text/plain;q=0.9,*/*;q=0.5");
|
|
172
189
|
}
|
|
173
190
|
try {
|
|
174
191
|
const response = await fetch(url, {
|
|
@@ -177,11 +194,31 @@ export function createFetchTools() {
|
|
|
177
194
|
redirect: "follow",
|
|
178
195
|
signal,
|
|
179
196
|
});
|
|
180
|
-
const text = await response.text();
|
|
181
|
-
const contentType = response.headers.get("content-type") ?? "";
|
|
182
197
|
if (!response.ok) {
|
|
183
198
|
throw new Error(`HTTP ${response.status} ${response.statusText}: GET ${url.toString()}`);
|
|
184
199
|
}
|
|
200
|
+
if (saveAs) {
|
|
201
|
+
const filePath = normalizeUserPath(saveAs);
|
|
202
|
+
const maxBytes = input.max_bytes ?? DEFAULT_MAX_BYTES;
|
|
203
|
+
const saved = await saveResponseToPath({
|
|
204
|
+
url,
|
|
205
|
+
response,
|
|
206
|
+
filePath,
|
|
207
|
+
maxBytes,
|
|
208
|
+
});
|
|
209
|
+
return toJsonValue({
|
|
210
|
+
url: url.toString(),
|
|
211
|
+
saved_as: filePath,
|
|
212
|
+
status: response.status,
|
|
213
|
+
statusText: response.statusText,
|
|
214
|
+
headers: responseHeaders(response.headers),
|
|
215
|
+
content_type: saved.contentType || null,
|
|
216
|
+
bytes_written: saved.bytesWritten,
|
|
217
|
+
max_bytes: maxBytes,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
const text = await response.text();
|
|
221
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
185
222
|
let transformed = text;
|
|
186
223
|
let transformedFormat = "raw";
|
|
187
224
|
let title;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch.js","sourceRoot":"","sources":["../../../src/core/tools/fetch.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"fetch.js","sourceRoot":"","sources":["../../../src/core/tools/fetch.ts"],"names":[],"mappings":"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"}
|
|
@@ -34,7 +34,8 @@ export declare function createFilesystemTools(): (import("@strands-agents/sdk").
|
|
|
34
34
|
paths: string[];
|
|
35
35
|
offset?: number | undefined;
|
|
36
36
|
limit?: number | undefined;
|
|
37
|
-
|
|
37
|
+
binary?: boolean | undefined;
|
|
38
|
+
}, JSONValue> | import("@strands-agents/sdk").InvokableTool<{
|
|
38
39
|
path: string;
|
|
39
40
|
content: string;
|
|
40
41
|
append?: boolean | undefined;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import fs from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import { tool } from "@strands-agents/sdk";
|
|
4
|
+
import { tool, TextBlock, } from "@strands-agents/sdk";
|
|
5
5
|
import { normalizeUserPath } from "../utils/normalize-user-path.js";
|
|
6
|
-
import { resolveAgentInstructionsForFile } from "../prompts/runtime.js";
|
|
6
|
+
import { resolveAgentInstructionsForFile } from "../prompts/runtime/agents.js";
|
|
7
7
|
import { setFileToolDisplay, } from "../state/file-tool-display.js";
|
|
8
8
|
import { readAttachmentAsBlocksOrBase64, } from "../utils/attachments.js";
|
|
9
9
|
import { findReplacementSpan, unescapeModelText, } from "../utils/edit-replace.js";
|
|
10
|
+
import { getLlmModality } from "../state/llm-modality.js";
|
|
10
11
|
import { z } from "zod";
|
|
11
12
|
import { createGitignorePredicate } from "../utils/gitignore.js";
|
|
12
13
|
/** Keyed by the Strands agent instance so backends are never serialized. */
|
|
@@ -295,6 +296,7 @@ async function readBinaryFile(filePath, options) {
|
|
|
295
296
|
includeMetadata: true,
|
|
296
297
|
unsupportedFormat: "base64",
|
|
297
298
|
onError: "throw",
|
|
299
|
+
metadata: options?.modality ?? null,
|
|
298
300
|
});
|
|
299
301
|
}
|
|
300
302
|
function snippetAroundChange(content, index, replacementLength) {
|
|
@@ -498,6 +500,10 @@ function createFilesystemSchema() {
|
|
|
498
500
|
paths: z.array(z.string()).min(1).describe("List of file paths to read."),
|
|
499
501
|
offset: z.number().int().min(1).optional(),
|
|
500
502
|
limit: z.number().int().min(1).optional(),
|
|
503
|
+
binary: z
|
|
504
|
+
.boolean()
|
|
505
|
+
.optional()
|
|
506
|
+
.describe("Read each path as binary. Images, videos, and documents become multimodal content blocks (when the model supports them); other binaries come back as base64. Offset/limit are ignored when binary is true."),
|
|
501
507
|
}),
|
|
502
508
|
writeFile: z.object({
|
|
503
509
|
path: z.string().describe("File path to write."),
|
|
@@ -571,7 +577,12 @@ export function createFilesystemTools() {
|
|
|
571
577
|
// Binary reads can return SDK media blocks (ImageBlock / DocumentBlock)
|
|
572
578
|
// or a plain base64 JSON object. Both are accepted by FunctionTool's
|
|
573
579
|
// result wrapping, but the callback signature is JSONValue, so cast.
|
|
574
|
-
|
|
580
|
+
// Pass the active LLM modality so images become ImageBlocks when the
|
|
581
|
+
// model supports them (otherwise we emit a text fallback diagnostic).
|
|
582
|
+
const modality = getLlmModality(context?.agent);
|
|
583
|
+
const result = await readBinaryFile(filePath, {
|
|
584
|
+
modality: modality ? { modality } : null,
|
|
585
|
+
});
|
|
575
586
|
return result;
|
|
576
587
|
}
|
|
577
588
|
const result = await readTextFile(filePath, {
|
|
@@ -587,9 +598,32 @@ export function createFilesystemTools() {
|
|
|
587
598
|
}),
|
|
588
599
|
tool({
|
|
589
600
|
name: "read_multiple_files",
|
|
590
|
-
description: "Read multiple
|
|
601
|
+
description: "Read multiple files in one call. Defaults to UTF-8 text with optional shared offset/limit. Pass `binary: true` to read each path as binary/multimodal (images, videos, documents) the same way as read_file.",
|
|
591
602
|
inputSchema: schema.readMultipleFiles,
|
|
592
603
|
callback: async (input, context) => {
|
|
604
|
+
if (input.binary) {
|
|
605
|
+
const modality = getLlmModality(context?.agent);
|
|
606
|
+
const blocks = [];
|
|
607
|
+
for (const itemPath of input.paths) {
|
|
608
|
+
const filePath = normalizeUserPath(itemPath);
|
|
609
|
+
blocks.push(new TextBlock(`==> ${filePath} <==`));
|
|
610
|
+
try {
|
|
611
|
+
const result = await readBinaryFile(filePath, {
|
|
612
|
+
modality: modality ? { modality } : null,
|
|
613
|
+
});
|
|
614
|
+
if (Array.isArray(result)) {
|
|
615
|
+
blocks.push(...result);
|
|
616
|
+
}
|
|
617
|
+
else {
|
|
618
|
+
blocks.push(new TextBlock(JSON.stringify(result)));
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
catch (error) {
|
|
622
|
+
blocks.push(new TextBlock(`[Error: ${error instanceof Error ? error.message : String(error)}]`));
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
return blocks;
|
|
626
|
+
}
|
|
593
627
|
const backend = getTextFsBackend(context?.agent);
|
|
594
628
|
const sections = await Promise.all(input.paths.map(async (itemPath) => {
|
|
595
629
|
const filePath = normalizeUserPath(itemPath);
|