@code-yeongyu/senpi 2026.7.11 → 2026.7.13
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 +17 -0
- package/dist/core/agent-session.d.ts +9 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +56 -15
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.d.ts.map +1 -1
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.js +76 -25
- package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.js.map +1 -1
- package/dist/core/resource-loader.d.ts +1 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +20 -2
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/modes/interactive/compaction-queue-transfer.d.ts +22 -0
- package/dist/modes/interactive/compaction-queue-transfer.d.ts.map +1 -0
- package/dist/modes/interactive/compaction-queue-transfer.js +82 -0
- package/dist/modes/interactive/compaction-queue-transfer.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +4 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +83 -69
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/node_modules/@babel/helper-string-parser/LICENSE +22 -0
- package/node_modules/@babel/helper-string-parser/README.md +19 -0
- package/node_modules/@babel/helper-string-parser/lib/index.js +295 -0
- package/node_modules/@babel/helper-string-parser/lib/index.js.map +1 -0
- package/node_modules/@babel/helper-string-parser/package.json +31 -0
- package/node_modules/@babel/helper-validator-identifier/LICENSE +22 -0
- package/node_modules/@babel/helper-validator-identifier/README.md +19 -0
- package/node_modules/@babel/helper-validator-identifier/lib/identifier.js +70 -0
- package/node_modules/@babel/helper-validator-identifier/lib/identifier.js.map +1 -0
- package/node_modules/@babel/helper-validator-identifier/lib/index.js +57 -0
- package/node_modules/@babel/helper-validator-identifier/lib/index.js.map +1 -0
- package/node_modules/@babel/helper-validator-identifier/lib/keyword.js +35 -0
- package/node_modules/@babel/helper-validator-identifier/lib/keyword.js.map +1 -0
- package/node_modules/@babel/helper-validator-identifier/package.json +31 -0
- package/node_modules/@babel/parser/LICENSE +19 -0
- package/node_modules/@babel/parser/README.md +19 -0
- package/node_modules/@babel/parser/bin/babel-parser.js +15 -0
- package/node_modules/@babel/parser/lib/index.js +14599 -0
- package/node_modules/@babel/parser/lib/index.js.map +1 -0
- package/node_modules/@babel/parser/package.json +50 -0
- package/node_modules/@babel/parser/typings/babel-parser.d.ts +262 -0
- package/node_modules/@babel/types/LICENSE +22 -0
- package/node_modules/@babel/types/README.md +19 -0
- package/node_modules/@babel/types/lib/asserts/assertNode.js +16 -0
- package/node_modules/@babel/types/lib/asserts/assertNode.js.map +1 -0
- package/node_modules/@babel/types/lib/asserts/generated/index.js +1251 -0
- package/node_modules/@babel/types/lib/asserts/generated/index.js.map +1 -0
- package/node_modules/@babel/types/lib/ast-types/generated/index.js +3 -0
- package/node_modules/@babel/types/lib/ast-types/generated/index.js.map +1 -0
- package/node_modules/@babel/types/lib/builders/flow/createFlowUnionType.js +18 -0
- package/node_modules/@babel/types/lib/builders/flow/createFlowUnionType.js.map +1 -0
- package/node_modules/@babel/types/lib/builders/flow/createTypeAnnotationBasedOnTypeof.js +31 -0
- package/node_modules/@babel/types/lib/builders/flow/createTypeAnnotationBasedOnTypeof.js.map +1 -0
- package/node_modules/@babel/types/lib/builders/generated/index.js +29 -0
- package/node_modules/@babel/types/lib/builders/generated/index.js.map +1 -0
- package/node_modules/@babel/types/lib/builders/generated/lowercase.js +2902 -0
- package/node_modules/@babel/types/lib/builders/generated/lowercase.js.map +1 -0
- package/node_modules/@babel/types/lib/builders/generated/uppercase.js +272 -0
- package/node_modules/@babel/types/lib/builders/generated/uppercase.js.map +1 -0
- package/node_modules/@babel/types/lib/builders/productions.js +12 -0
- package/node_modules/@babel/types/lib/builders/productions.js.map +1 -0
- package/node_modules/@babel/types/lib/builders/react/buildChildren.js +24 -0
- package/node_modules/@babel/types/lib/builders/react/buildChildren.js.map +1 -0
- package/node_modules/@babel/types/lib/builders/typescript/createTSUnionType.js +22 -0
- package/node_modules/@babel/types/lib/builders/typescript/createTSUnionType.js.map +1 -0
- package/node_modules/@babel/types/lib/builders/validateNode.js +21 -0
- package/node_modules/@babel/types/lib/builders/validateNode.js.map +1 -0
- package/node_modules/@babel/types/lib/clone/clone.js +12 -0
- package/node_modules/@babel/types/lib/clone/clone.js.map +1 -0
- package/node_modules/@babel/types/lib/clone/cloneDeep.js +12 -0
- package/node_modules/@babel/types/lib/clone/cloneDeep.js.map +1 -0
- package/node_modules/@babel/types/lib/clone/cloneDeepWithoutLoc.js +12 -0
- package/node_modules/@babel/types/lib/clone/cloneDeepWithoutLoc.js.map +1 -0
- package/node_modules/@babel/types/lib/clone/cloneNode.js +107 -0
- package/node_modules/@babel/types/lib/clone/cloneNode.js.map +1 -0
- package/node_modules/@babel/types/lib/clone/cloneWithoutLoc.js +12 -0
- package/node_modules/@babel/types/lib/clone/cloneWithoutLoc.js.map +1 -0
- package/node_modules/@babel/types/lib/comments/addComment.js +15 -0
- package/node_modules/@babel/types/lib/comments/addComment.js.map +1 -0
- package/node_modules/@babel/types/lib/comments/addComments.js +22 -0
- package/node_modules/@babel/types/lib/comments/addComments.js.map +1 -0
- package/node_modules/@babel/types/lib/comments/inheritInnerComments.js +12 -0
- package/node_modules/@babel/types/lib/comments/inheritInnerComments.js.map +1 -0
- package/node_modules/@babel/types/lib/comments/inheritLeadingComments.js +12 -0
- package/node_modules/@babel/types/lib/comments/inheritLeadingComments.js.map +1 -0
- package/node_modules/@babel/types/lib/comments/inheritTrailingComments.js +12 -0
- package/node_modules/@babel/types/lib/comments/inheritTrailingComments.js.map +1 -0
- package/node_modules/@babel/types/lib/comments/inheritsComments.js +17 -0
- package/node_modules/@babel/types/lib/comments/inheritsComments.js.map +1 -0
- package/node_modules/@babel/types/lib/comments/removeComments.js +15 -0
- package/node_modules/@babel/types/lib/comments/removeComments.js.map +1 -0
- package/node_modules/@babel/types/lib/constants/generated/index.js +60 -0
- package/node_modules/@babel/types/lib/constants/generated/index.js.map +1 -0
- package/node_modules/@babel/types/lib/constants/index.js +31 -0
- package/node_modules/@babel/types/lib/constants/index.js.map +1 -0
- package/node_modules/@babel/types/lib/converters/ensureBlock.js +14 -0
- package/node_modules/@babel/types/lib/converters/ensureBlock.js.map +1 -0
- package/node_modules/@babel/types/lib/converters/gatherSequenceExpressions.js +65 -0
- package/node_modules/@babel/types/lib/converters/gatherSequenceExpressions.js.map +1 -0
- package/node_modules/@babel/types/lib/converters/toBindingIdentifierName.js +14 -0
- package/node_modules/@babel/types/lib/converters/toBindingIdentifierName.js.map +1 -0
- package/node_modules/@babel/types/lib/converters/toBlock.js +29 -0
- package/node_modules/@babel/types/lib/converters/toBlock.js.map +1 -0
- package/node_modules/@babel/types/lib/converters/toComputedKey.js +14 -0
- package/node_modules/@babel/types/lib/converters/toComputedKey.js.map +1 -0
- package/node_modules/@babel/types/lib/converters/toExpression.js +28 -0
- package/node_modules/@babel/types/lib/converters/toExpression.js.map +1 -0
- package/node_modules/@babel/types/lib/converters/toIdentifier.js +25 -0
- package/node_modules/@babel/types/lib/converters/toIdentifier.js.map +1 -0
- package/node_modules/@babel/types/lib/converters/toKeyAlias.js +38 -0
- package/node_modules/@babel/types/lib/converters/toKeyAlias.js.map +1 -0
- package/node_modules/@babel/types/lib/converters/toSequenceExpression.js +19 -0
- package/node_modules/@babel/types/lib/converters/toSequenceExpression.js.map +1 -0
- package/node_modules/@babel/types/lib/converters/toStatement.js +39 -0
- package/node_modules/@babel/types/lib/converters/toStatement.js.map +1 -0
- package/node_modules/@babel/types/lib/converters/valueToNode.js +89 -0
- package/node_modules/@babel/types/lib/converters/valueToNode.js.map +1 -0
- package/node_modules/@babel/types/lib/definitions/core.js +1725 -0
- package/node_modules/@babel/types/lib/definitions/core.js.map +1 -0
- package/node_modules/@babel/types/lib/definitions/deprecated-aliases.js +11 -0
- package/node_modules/@babel/types/lib/definitions/deprecated-aliases.js.map +1 -0
- package/node_modules/@babel/types/lib/definitions/experimental.js +124 -0
- package/node_modules/@babel/types/lib/definitions/experimental.js.map +1 -0
- package/node_modules/@babel/types/lib/definitions/flow.js +495 -0
- package/node_modules/@babel/types/lib/definitions/flow.js.map +1 -0
- package/node_modules/@babel/types/lib/definitions/index.js +106 -0
- package/node_modules/@babel/types/lib/definitions/index.js.map +1 -0
- package/node_modules/@babel/types/lib/definitions/jsx.js +157 -0
- package/node_modules/@babel/types/lib/definitions/jsx.js.map +1 -0
- package/node_modules/@babel/types/lib/definitions/misc.js +31 -0
- package/node_modules/@babel/types/lib/definitions/misc.js.map +1 -0
- package/node_modules/@babel/types/lib/definitions/placeholders.js +27 -0
- package/node_modules/@babel/types/lib/definitions/placeholders.js.map +1 -0
- package/node_modules/@babel/types/lib/definitions/typescript.js +528 -0
- package/node_modules/@babel/types/lib/definitions/typescript.js.map +1 -0
- package/node_modules/@babel/types/lib/definitions/utils.js +296 -0
- package/node_modules/@babel/types/lib/definitions/utils.js.map +1 -0
- package/node_modules/@babel/types/lib/index-legacy.d.ts +2797 -0
- package/node_modules/@babel/types/lib/index.d.ts +3617 -0
- package/node_modules/@babel/types/lib/index.js +582 -0
- package/node_modules/@babel/types/lib/index.js.flow +2650 -0
- package/node_modules/@babel/types/lib/index.js.map +1 -0
- package/node_modules/@babel/types/lib/modifications/appendToMemberExpression.js +15 -0
- package/node_modules/@babel/types/lib/modifications/appendToMemberExpression.js.map +1 -0
- package/node_modules/@babel/types/lib/modifications/flow/removeTypeDuplicates.js +65 -0
- package/node_modules/@babel/types/lib/modifications/flow/removeTypeDuplicates.js.map +1 -0
- package/node_modules/@babel/types/lib/modifications/inherits.js +28 -0
- package/node_modules/@babel/types/lib/modifications/inherits.js.map +1 -0
- package/node_modules/@babel/types/lib/modifications/prependToMemberExpression.js +17 -0
- package/node_modules/@babel/types/lib/modifications/prependToMemberExpression.js.map +1 -0
- package/node_modules/@babel/types/lib/modifications/removeProperties.js +24 -0
- package/node_modules/@babel/types/lib/modifications/removeProperties.js.map +1 -0
- package/node_modules/@babel/types/lib/modifications/removePropertiesDeep.js +14 -0
- package/node_modules/@babel/types/lib/modifications/removePropertiesDeep.js.map +1 -0
- package/node_modules/@babel/types/lib/modifications/typescript/removeTypeDuplicates.js +66 -0
- package/node_modules/@babel/types/lib/modifications/typescript/removeTypeDuplicates.js.map +1 -0
- package/node_modules/@babel/types/lib/retrievers/getAssignmentIdentifiers.js +48 -0
- package/node_modules/@babel/types/lib/retrievers/getAssignmentIdentifiers.js.map +1 -0
- package/node_modules/@babel/types/lib/retrievers/getBindingIdentifiers.js +102 -0
- package/node_modules/@babel/types/lib/retrievers/getBindingIdentifiers.js.map +1 -0
- package/node_modules/@babel/types/lib/retrievers/getFunctionName.js +63 -0
- package/node_modules/@babel/types/lib/retrievers/getFunctionName.js.map +1 -0
- package/node_modules/@babel/types/lib/retrievers/getOuterBindingIdentifiers.js +13 -0
- package/node_modules/@babel/types/lib/retrievers/getOuterBindingIdentifiers.js.map +1 -0
- package/node_modules/@babel/types/lib/traverse/traverse.js +50 -0
- package/node_modules/@babel/types/lib/traverse/traverse.js.map +1 -0
- package/node_modules/@babel/types/lib/traverse/traverseFast.js +40 -0
- package/node_modules/@babel/types/lib/traverse/traverseFast.js.map +1 -0
- package/node_modules/@babel/types/lib/utils/deprecationWarning.js +44 -0
- package/node_modules/@babel/types/lib/utils/deprecationWarning.js.map +1 -0
- package/node_modules/@babel/types/lib/utils/inherit.js +13 -0
- package/node_modules/@babel/types/lib/utils/inherit.js.map +1 -0
- package/node_modules/@babel/types/lib/utils/react/cleanJSXElementLiteralChild.js +40 -0
- package/node_modules/@babel/types/lib/utils/react/cleanJSXElementLiteralChild.js.map +1 -0
- package/node_modules/@babel/types/lib/utils/shallowEqual.js +17 -0
- package/node_modules/@babel/types/lib/utils/shallowEqual.js.map +1 -0
- package/node_modules/@babel/types/lib/validators/buildMatchMemberExpression.js +13 -0
- package/node_modules/@babel/types/lib/validators/buildMatchMemberExpression.js.map +1 -0
- package/node_modules/@babel/types/lib/validators/generated/index.js +2797 -0
- package/node_modules/@babel/types/lib/validators/generated/index.js.map +1 -0
- package/node_modules/@babel/types/lib/validators/is.js +27 -0
- package/node_modules/@babel/types/lib/validators/is.js.map +1 -0
- package/node_modules/@babel/types/lib/validators/isBinding.js +27 -0
- package/node_modules/@babel/types/lib/validators/isBinding.js.map +1 -0
- package/node_modules/@babel/types/lib/validators/isBlockScoped.js +13 -0
- package/node_modules/@babel/types/lib/validators/isBlockScoped.js.map +1 -0
- package/node_modules/@babel/types/lib/validators/isImmutable.js +21 -0
- package/node_modules/@babel/types/lib/validators/isImmutable.js.map +1 -0
- package/node_modules/@babel/types/lib/validators/isLet.js +13 -0
- package/node_modules/@babel/types/lib/validators/isLet.js.map +1 -0
- package/node_modules/@babel/types/lib/validators/isNode.js +12 -0
- package/node_modules/@babel/types/lib/validators/isNode.js.map +1 -0
- package/node_modules/@babel/types/lib/validators/isNodesEquivalent.js +57 -0
- package/node_modules/@babel/types/lib/validators/isNodesEquivalent.js.map +1 -0
- package/node_modules/@babel/types/lib/validators/isPlaceholderType.js +15 -0
- package/node_modules/@babel/types/lib/validators/isPlaceholderType.js.map +1 -0
- package/node_modules/@babel/types/lib/validators/isReferenced.js +96 -0
- package/node_modules/@babel/types/lib/validators/isReferenced.js.map +1 -0
- package/node_modules/@babel/types/lib/validators/isScope.js +18 -0
- package/node_modules/@babel/types/lib/validators/isScope.js.map +1 -0
- package/node_modules/@babel/types/lib/validators/isSpecifierDefault.js +14 -0
- package/node_modules/@babel/types/lib/validators/isSpecifierDefault.js.map +1 -0
- package/node_modules/@babel/types/lib/validators/isType.js +17 -0
- package/node_modules/@babel/types/lib/validators/isType.js.map +1 -0
- package/node_modules/@babel/types/lib/validators/isValidES3Identifier.js +13 -0
- package/node_modules/@babel/types/lib/validators/isValidES3Identifier.js.map +1 -0
- package/node_modules/@babel/types/lib/validators/isValidIdentifier.js +18 -0
- package/node_modules/@babel/types/lib/validators/isValidIdentifier.js.map +1 -0
- package/node_modules/@babel/types/lib/validators/isVar.js +15 -0
- package/node_modules/@babel/types/lib/validators/isVar.js.map +1 -0
- package/node_modules/@babel/types/lib/validators/matchesPattern.js +44 -0
- package/node_modules/@babel/types/lib/validators/matchesPattern.js.map +1 -0
- package/node_modules/@babel/types/lib/validators/react/isCompatTag.js +11 -0
- package/node_modules/@babel/types/lib/validators/react/isCompatTag.js.map +1 -0
- package/node_modules/@babel/types/lib/validators/react/isReactComponent.js +11 -0
- package/node_modules/@babel/types/lib/validators/react/isReactComponent.js.map +1 -0
- package/node_modules/@babel/types/lib/validators/validate.js +42 -0
- package/node_modules/@babel/types/lib/validators/validate.js.map +1 -0
- package/node_modules/@babel/types/package.json +39 -0
- package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +10 -2
- package/node_modules/@code-yeongyu/senpi-codemode/README.md +128 -78
- package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -3
- package/node_modules/@code-yeongyu/senpi-codemode/src/bridge/protocol.ts +15 -2
- package/node_modules/@code-yeongyu/senpi-codemode/src/bridge/reserved.ts +9 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/bridges/agent-bridge.ts +197 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/bridges/output-bridge.ts +96 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/bridges/schema-injection.ts +3 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/completion/handler.ts +95 -26
- package/node_modules/@code-yeongyu/senpi-codemode/src/completion/tool-bridge.ts +11 -2
- package/node_modules/@code-yeongyu/senpi-codemode/src/config/settings.ts +96 -8
- package/node_modules/@code-yeongyu/senpi-codemode/src/extension/session-manager.ts +24 -3
- package/node_modules/@code-yeongyu/senpi-codemode/src/index.ts +155 -21
- package/node_modules/@code-yeongyu/senpi-codemode/src/interpreters/detect.ts +1 -1
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/jl/prelude.jl +252 -48
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/jl/runner.jl +263 -83
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/context-manager.ts +11 -5
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/local-module-loader.ts +108 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/prelude.ts +8 -6
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/rewrite-imports.ts +164 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-core.js +6 -1
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-runtime.js +307 -41
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/py/kernel.ts +3 -2
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/py/prelude.py +792 -79
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/rb/prelude.rb +234 -21
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/rb/runner.rb +154 -51
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/shared/subprocess-queue.ts +1 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/output/output-meta.ts +89 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/output/streaming-output.ts +296 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/prompt/eval-prompt.ts +107 -30
- package/node_modules/@code-yeongyu/senpi-codemode/src/timeouts/bridge-timeout.ts +2 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/timeouts/idle-timeout.ts +8 -19
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/cell-handler.ts +175 -113
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/eval-tool.ts +130 -120
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/image.ts +274 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/json-tree.ts +247 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/render.ts +641 -38
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/status-events.ts +12 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/types.ts +29 -1
- package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
- package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.js +16 -16
- package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.js +6 -6
- package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/package.json +2 -2
- package/node_modules/@earendil-works/pi-pty/package.json +1 -1
- package/node_modules/@earendil-works/pi-tui/package.json +1 -1
- package/package.json +6 -6
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
// allow: SIZE_OK — one eval render pipeline avoids the runtime/render TDZ that motivated this module boundary.
|
|
1
2
|
import {
|
|
2
3
|
type AgentToolResult,
|
|
4
|
+
highlightCode,
|
|
3
5
|
sanitizeTerminalLabel,
|
|
4
6
|
type Theme,
|
|
5
7
|
type ThemeColor,
|
|
@@ -7,12 +9,34 @@ import {
|
|
|
7
9
|
type ToolRenderResultOptions,
|
|
8
10
|
truncateToVisualLines,
|
|
9
11
|
} from "@code-yeongyu/senpi";
|
|
10
|
-
import
|
|
12
|
+
import { formatTruncationWarning, stripOutputNotice, type TruncationMeta } from "../output/output-meta.ts";
|
|
13
|
+
import {
|
|
14
|
+
JSON_TREE_MAX_DEPTH_COLLAPSED,
|
|
15
|
+
JSON_TREE_MAX_DEPTH_EXPANDED,
|
|
16
|
+
JSON_TREE_MAX_LINES_COLLAPSED,
|
|
17
|
+
JSON_TREE_MAX_LINES_EXPANDED,
|
|
18
|
+
JSON_TREE_SCALAR_LEN_COLLAPSED,
|
|
19
|
+
JSON_TREE_SCALAR_LEN_EXPANDED,
|
|
20
|
+
renderJsonTreeLines,
|
|
21
|
+
} from "./json-tree.ts";
|
|
22
|
+
import type {
|
|
23
|
+
EvalCellResult,
|
|
24
|
+
EvalInputSchema,
|
|
25
|
+
EvalLanguage,
|
|
26
|
+
EvalStatusEvent,
|
|
27
|
+
EvalToolDetails,
|
|
28
|
+
EvalToolInput,
|
|
29
|
+
} from "./types.ts";
|
|
11
30
|
|
|
12
|
-
type EvalToolDefinition = ToolDefinition<
|
|
31
|
+
type EvalToolDefinition = ToolDefinition<EvalInputSchema, EvalToolDetails>;
|
|
13
32
|
type RenderContext = Parameters<NonNullable<EvalToolDefinition["renderCall"]>>[2];
|
|
14
|
-
type
|
|
33
|
+
type ResultRenderContext = Parameters<NonNullable<EvalToolDefinition["renderResult"]>>[3];
|
|
15
34
|
type CollapsibleKind = "code" | "output";
|
|
35
|
+
|
|
36
|
+
export interface EvalRenderComponent {
|
|
37
|
+
render(width: number): string[];
|
|
38
|
+
invalidate(): void;
|
|
39
|
+
}
|
|
16
40
|
type ToolCallRow = {
|
|
17
41
|
readonly summary: string;
|
|
18
42
|
readonly error?: string;
|
|
@@ -32,16 +56,19 @@ type RenderBlock =
|
|
|
32
56
|
readonly calls: readonly ToolCallRow[];
|
|
33
57
|
readonly expanded: boolean;
|
|
34
58
|
readonly theme?: Theme;
|
|
35
|
-
}
|
|
59
|
+
}
|
|
60
|
+
| { readonly kind: "dynamic"; readonly render: (width: number) => readonly string[] };
|
|
36
61
|
|
|
37
62
|
const CODE_PREVIEW_LINES = 4;
|
|
38
63
|
const OUTPUT_PREVIEW_LINES = 8;
|
|
64
|
+
const STATUS_PREVIEW_COUNT = 3;
|
|
65
|
+
const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"] as const;
|
|
39
66
|
const TOOL_CALL_PREVIEW_COUNT = 5;
|
|
40
67
|
const TOOL_CALL_COLLAPSED_VISUAL_LINES = 4;
|
|
41
68
|
const TOOL_CALL_COLLAPSED_ERROR_CODE_POINTS = 512;
|
|
42
69
|
const TOOL_ERROR_OMISSION_MARKER = "[tool error omitted]";
|
|
43
70
|
|
|
44
|
-
class PlainTextComponent {
|
|
71
|
+
class PlainTextComponent implements EvalRenderComponent {
|
|
45
72
|
#blocks: readonly RenderBlock[] = [];
|
|
46
73
|
|
|
47
74
|
setBlocks(blocks: readonly RenderBlock[]): void {
|
|
@@ -51,12 +78,21 @@ class PlainTextComponent {
|
|
|
51
78
|
render(width: number): string[] {
|
|
52
79
|
const lines: string[] = [];
|
|
53
80
|
for (const block of this.#blocks) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
81
|
+
switch (block.kind) {
|
|
82
|
+
case "blank":
|
|
83
|
+
lines.push("");
|
|
84
|
+
break;
|
|
85
|
+
case "toolCalls":
|
|
86
|
+
appendLines(lines, renderToolCallBlock(block, width));
|
|
87
|
+
break;
|
|
88
|
+
case "text":
|
|
89
|
+
appendLines(lines, renderTextBlock(block, width));
|
|
90
|
+
break;
|
|
91
|
+
case "dynamic":
|
|
92
|
+
appendLines(lines, block.render(width));
|
|
93
|
+
break;
|
|
94
|
+
default:
|
|
95
|
+
assertNever(block);
|
|
60
96
|
}
|
|
61
97
|
}
|
|
62
98
|
return lines;
|
|
@@ -65,7 +101,7 @@ class PlainTextComponent {
|
|
|
65
101
|
invalidate(): void {}
|
|
66
102
|
}
|
|
67
103
|
|
|
68
|
-
function componentFor(context: RenderContext): PlainTextComponent {
|
|
104
|
+
function componentFor(context: RenderContext | ResultRenderContext): PlainTextComponent {
|
|
69
105
|
const existing = context.lastComponent;
|
|
70
106
|
if (existing instanceof PlainTextComponent) return existing;
|
|
71
107
|
return new PlainTextComponent();
|
|
@@ -152,8 +188,473 @@ function renderToolCallBlock(block: Extract<RenderBlock, { kind: "toolCalls" }>,
|
|
|
152
188
|
return lines;
|
|
153
189
|
}
|
|
154
190
|
|
|
155
|
-
|
|
156
|
-
|
|
191
|
+
type CellStatus = EvalCellResult["status"];
|
|
192
|
+
type AgentStatus = "pending" | "running" | "completed" | "failed" | "aborted";
|
|
193
|
+
type StatusPresentation = { readonly label: string; readonly icon: string; readonly color: ThemeColor };
|
|
194
|
+
type RenderEnvironment = {
|
|
195
|
+
readonly expanded: boolean;
|
|
196
|
+
readonly theme: Theme | undefined;
|
|
197
|
+
readonly spinnerFrame: number | undefined;
|
|
198
|
+
readonly width: number;
|
|
199
|
+
readonly meta: TruncationMeta | undefined;
|
|
200
|
+
};
|
|
201
|
+
type CellBadges = { readonly reset: boolean; readonly timeout: number | undefined };
|
|
202
|
+
type PrefixStyle = { readonly prefix: string; readonly continuation: string; readonly color: ThemeColor };
|
|
203
|
+
type DetailedRenderContext = {
|
|
204
|
+
readonly environment: RenderEnvironment;
|
|
205
|
+
readonly args: EvalToolInput;
|
|
206
|
+
readonly showImageFallback: boolean;
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
function assertNever(value: never): never {
|
|
210
|
+
throw new TypeError(`Unhandled eval render variant: ${String(value)}`);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function languageForHighlighter(language: EvalLanguage): "python" | "javascript" | "ruby" | "julia" {
|
|
214
|
+
switch (language) {
|
|
215
|
+
case "py":
|
|
216
|
+
return "python";
|
|
217
|
+
case "js":
|
|
218
|
+
return "javascript";
|
|
219
|
+
case "rb":
|
|
220
|
+
return "ruby";
|
|
221
|
+
case "jl":
|
|
222
|
+
return "julia";
|
|
223
|
+
default:
|
|
224
|
+
return assertNever(language);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function highlightedCode(code: string, language: EvalLanguage, theme: Theme | undefined): string {
|
|
229
|
+
const normalizedCode = code.trim().length > 0 ? code : "...";
|
|
230
|
+
const lines = highlightCode(normalizedCode, languageForHighlighter(language));
|
|
231
|
+
return (theme === undefined ? lines.map((line) => line.replace(/\u001b\[[0-9;]*m/gu, "")) : lines).join("\n");
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function formatDuration(milliseconds: number): string {
|
|
235
|
+
const totalSeconds = Math.floor(Math.max(0, milliseconds) / 1_000);
|
|
236
|
+
if (totalSeconds < 1) return "<1s";
|
|
237
|
+
const seconds = totalSeconds % 60;
|
|
238
|
+
const totalMinutes = Math.floor(totalSeconds / 60);
|
|
239
|
+
if (totalMinutes < 1) return `${seconds}s`;
|
|
240
|
+
const minutes = totalMinutes % 60;
|
|
241
|
+
const hours = Math.floor(totalMinutes / 60);
|
|
242
|
+
if (hours < 1) return seconds === 0 ? `${minutes}m` : `${minutes}m ${seconds}s`;
|
|
243
|
+
return minutes === 0 ? `${hours}h` : `${hours}h ${minutes}m`;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function spinner(frame: number | undefined): string {
|
|
247
|
+
return SPINNER_FRAMES.at((frame ?? 0) % SPINNER_FRAMES.length) ?? SPINNER_FRAMES[0];
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function cellPresentation(status: CellStatus, spinnerFrame: number | undefined): StatusPresentation {
|
|
251
|
+
switch (status) {
|
|
252
|
+
case "pending":
|
|
253
|
+
return { label: "pending", icon: "○", color: "muted" };
|
|
254
|
+
case "running":
|
|
255
|
+
return { label: "running", icon: spinner(spinnerFrame), color: "warning" };
|
|
256
|
+
case "complete":
|
|
257
|
+
return { label: "done", icon: "✓", color: "success" };
|
|
258
|
+
case "error":
|
|
259
|
+
return { label: "error", icon: "✗", color: "error" };
|
|
260
|
+
default:
|
|
261
|
+
return assertNever(status);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function renderPrefixed(text: string, environment: RenderEnvironment, prefixStyle: PrefixStyle): string[] {
|
|
266
|
+
const bodyLines = renderAllVisualLines(text, Math.max(1, environment.width - prefixStyle.prefix.length));
|
|
267
|
+
if (bodyLines.length === 0) return [style(environment.theme, prefixStyle.color, prefixStyle.prefix.trimEnd())];
|
|
268
|
+
return bodyLines.map(
|
|
269
|
+
(line, index) =>
|
|
270
|
+
`${style(environment.theme, prefixStyle.color, index === 0 ? prefixStyle.prefix : prefixStyle.continuation)}${line}`,
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function cellHeader(cell: EvalCellResult, environment: RenderEnvironment, badges: CellBadges): string {
|
|
275
|
+
const presentation = cellPresentation(cell.status, environment.spinnerFrame);
|
|
276
|
+
const title = cell.title === undefined ? "" : ` ${cell.title}`;
|
|
277
|
+
let header = `eval ${cell.language}${title} ${presentation.label} ${presentation.icon}`;
|
|
278
|
+
if (cell.durationMs !== undefined) header += ` · ${formatDuration(cell.durationMs)}`;
|
|
279
|
+
if (badges.reset) header += " · reset";
|
|
280
|
+
if (badges.timeout !== undefined) header += ` · timeout ${badges.timeout}s`;
|
|
281
|
+
return style(environment.theme, presentation.color, header);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function previewText(
|
|
285
|
+
text: string,
|
|
286
|
+
maxLines: number,
|
|
287
|
+
width: number,
|
|
288
|
+
): { readonly lines: string[]; readonly skipped: number } {
|
|
289
|
+
const preview = truncateToVisualLines(text, maxLines, Math.max(1, width));
|
|
290
|
+
return { lines: preview.visualLines.map((line) => line.trimEnd()), skipped: preview.skippedCount };
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function eventString(value: unknown): string | undefined {
|
|
294
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function eventNumber(value: unknown): number {
|
|
298
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function plural(count: number, singular: string, pluralNoun: string): string {
|
|
302
|
+
return `${count} ${count === 1 ? singular : pluralNoun}`;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function statusIcon(op: string): string {
|
|
306
|
+
if (op.startsWith("git_")) return "⌁";
|
|
307
|
+
switch (op) {
|
|
308
|
+
case "read":
|
|
309
|
+
case "write":
|
|
310
|
+
case "cat":
|
|
311
|
+
case "touch":
|
|
312
|
+
return "▣";
|
|
313
|
+
case "ls":
|
|
314
|
+
case "cd":
|
|
315
|
+
case "pwd":
|
|
316
|
+
case "mkdir":
|
|
317
|
+
return "▤";
|
|
318
|
+
case "run":
|
|
319
|
+
case "sh":
|
|
320
|
+
return "▶";
|
|
321
|
+
case "completion":
|
|
322
|
+
return "◇";
|
|
323
|
+
case "phase":
|
|
324
|
+
return "◆";
|
|
325
|
+
default:
|
|
326
|
+
return "•";
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function formatStatusEvent(event: EvalStatusEvent, theme: Theme | undefined): string {
|
|
331
|
+
const op = event.op;
|
|
332
|
+
const icon = style(theme, "muted", statusIcon(op));
|
|
333
|
+
const error = eventString(event["error"]);
|
|
334
|
+
if (error !== undefined) return `${icon} ${style(theme, "warning", op)}: ${style(theme, "dim", error)}`;
|
|
335
|
+
const parts: string[] = [];
|
|
336
|
+
switch (op) {
|
|
337
|
+
case "read": {
|
|
338
|
+
parts.push(`${eventNumber(event["chars"] ?? event["bytes"])} chars`);
|
|
339
|
+
const path = eventString(event["path"]);
|
|
340
|
+
if (path !== undefined) parts.push(`from ${path}`);
|
|
341
|
+
break;
|
|
342
|
+
}
|
|
343
|
+
case "write": {
|
|
344
|
+
parts.push(`${eventNumber(event["chars"] ?? event["bytes"])} chars`);
|
|
345
|
+
const path = eventString(event["path"]);
|
|
346
|
+
if (path !== undefined) parts.push(`to ${path}`);
|
|
347
|
+
break;
|
|
348
|
+
}
|
|
349
|
+
case "cat":
|
|
350
|
+
parts.push(plural(eventNumber(event["files"]), "file", "files"));
|
|
351
|
+
parts.push(`${eventNumber(event["chars"])} chars`);
|
|
352
|
+
break;
|
|
353
|
+
case "ls":
|
|
354
|
+
parts.push(plural(eventNumber(event["count"]), "entry", "entries"));
|
|
355
|
+
break;
|
|
356
|
+
case "env": {
|
|
357
|
+
const action = eventString(event["action"]);
|
|
358
|
+
const key = eventString(event["key"]);
|
|
359
|
+
const value = eventString(event["value"]) ?? "";
|
|
360
|
+
if (action === "set" && key !== undefined) parts.push(`set ${key}=${value.slice(0, 30)}`);
|
|
361
|
+
else if (action === "get" && key !== undefined) parts.push(`${key}=${value.slice(0, 30)}`);
|
|
362
|
+
else parts.push(plural(eventNumber(event["count"]), "variable", "variables"));
|
|
363
|
+
break;
|
|
364
|
+
}
|
|
365
|
+
case "git_status": {
|
|
366
|
+
if (event["clean"] === true) parts.push("clean");
|
|
367
|
+
else {
|
|
368
|
+
const changes: string[] = [];
|
|
369
|
+
for (const key of ["staged", "modified", "untracked"] as const) {
|
|
370
|
+
const count = eventNumber(event[key]);
|
|
371
|
+
if (count > 0) changes.push(`${count} ${key}`);
|
|
372
|
+
}
|
|
373
|
+
parts.push(changes.join(", ") || "unknown");
|
|
374
|
+
}
|
|
375
|
+
const branch = eventString(event["branch"]);
|
|
376
|
+
if (branch !== undefined) parts.push(`on ${branch}`);
|
|
377
|
+
break;
|
|
378
|
+
}
|
|
379
|
+
case "git_diff":
|
|
380
|
+
parts.push(plural(eventNumber(event["lines"]), "line", "lines"));
|
|
381
|
+
if (event["staged"] === true) parts.push("staged");
|
|
382
|
+
break;
|
|
383
|
+
case "git_log":
|
|
384
|
+
parts.push(plural(eventNumber(event["commits"]), "commit", "commits"));
|
|
385
|
+
break;
|
|
386
|
+
case "run":
|
|
387
|
+
case "sh": {
|
|
388
|
+
const command = eventString(event["command"] ?? event["cmd"]);
|
|
389
|
+
if (command !== undefined) parts.push(command);
|
|
390
|
+
if (typeof event["exitCode"] === "number") parts.push(`exit ${event["exitCode"]}`);
|
|
391
|
+
break;
|
|
392
|
+
}
|
|
393
|
+
case "completion": {
|
|
394
|
+
const model = eventString(event["model"]);
|
|
395
|
+
const tier = eventString(event["tier"]);
|
|
396
|
+
if (model !== undefined) parts.push(model);
|
|
397
|
+
if (tier !== undefined && tier !== model) parts.push(tier);
|
|
398
|
+
parts.push(`${eventNumber(event["chars"])} chars`);
|
|
399
|
+
break;
|
|
400
|
+
}
|
|
401
|
+
case "log":
|
|
402
|
+
parts.push(eventString(event["message"]) ?? "");
|
|
403
|
+
break;
|
|
404
|
+
case "phase":
|
|
405
|
+
parts.push(eventString(event["title"]) ?? "");
|
|
406
|
+
break;
|
|
407
|
+
default: {
|
|
408
|
+
if (event["count"] !== undefined) parts.push(String(event["count"]));
|
|
409
|
+
const path = eventString(event["path"]);
|
|
410
|
+
if (path !== undefined) parts.push(path);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
const description = parts.filter((part) => part.length > 0).join(" · ");
|
|
414
|
+
return `${icon} ${style(theme, "muted", op)}${description.length > 0 ? ` ${style(theme, "dim", description)}` : ""}`;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
function renderStatusEvents(events: readonly EvalStatusEvent[], environment: RenderEnvironment): string[] {
|
|
418
|
+
const retained = environment.expanded ? events : events.slice(-STATUS_PREVIEW_COUNT);
|
|
419
|
+
const skipped = events.length - retained.length;
|
|
420
|
+
const lines: string[] = [];
|
|
421
|
+
if (skipped > 0) lines.push(style(environment.theme, "dim", `├ … ${skipped} earlier status events`));
|
|
422
|
+
for (const [index, event] of retained.entries()) {
|
|
423
|
+
const branch = index === retained.length - 1 ? "└" : "├";
|
|
424
|
+
lines.push(`${style(environment.theme, "dim", branch)} ${formatStatusEvent(event, environment.theme)}`);
|
|
425
|
+
}
|
|
426
|
+
return lines;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
function agentStatus(value: unknown): AgentStatus {
|
|
430
|
+
switch (value) {
|
|
431
|
+
case "pending":
|
|
432
|
+
case "running":
|
|
433
|
+
case "completed":
|
|
434
|
+
case "failed":
|
|
435
|
+
case "aborted":
|
|
436
|
+
return value;
|
|
437
|
+
default:
|
|
438
|
+
return "running";
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
function coalesceAgentEvents(events: readonly EvalStatusEvent[]): EvalStatusEvent[] {
|
|
443
|
+
const rows: EvalStatusEvent[] = [];
|
|
444
|
+
const indexes = new Map<string, number>();
|
|
445
|
+
for (const event of events) {
|
|
446
|
+
const id = eventString(event["id"]);
|
|
447
|
+
if (id === undefined) {
|
|
448
|
+
rows.push(event);
|
|
449
|
+
continue;
|
|
450
|
+
}
|
|
451
|
+
const index = indexes.get(id);
|
|
452
|
+
if (index === undefined) {
|
|
453
|
+
indexes.set(id, rows.length);
|
|
454
|
+
rows.push(event);
|
|
455
|
+
} else rows[index] = event;
|
|
456
|
+
}
|
|
457
|
+
return rows;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
function agentPresentation(status: AgentStatus, spinnerFrame: number | undefined): StatusPresentation {
|
|
461
|
+
switch (status) {
|
|
462
|
+
case "pending":
|
|
463
|
+
return { label: "pending", icon: "○", color: "muted" };
|
|
464
|
+
case "running":
|
|
465
|
+
return { label: "running", icon: spinner(spinnerFrame), color: "warning" };
|
|
466
|
+
case "completed":
|
|
467
|
+
return { label: "done", icon: "✓", color: "success" };
|
|
468
|
+
case "failed":
|
|
469
|
+
return { label: "failed", icon: "✗", color: "error" };
|
|
470
|
+
case "aborted":
|
|
471
|
+
return { label: "aborted", icon: "×", color: "error" };
|
|
472
|
+
default:
|
|
473
|
+
return assertNever(status);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function renderAgentProgressEvents(events: readonly EvalStatusEvent[], environment: RenderEnvironment): string[] {
|
|
478
|
+
const rows = coalesceAgentEvents(events);
|
|
479
|
+
const lines: string[] = [];
|
|
480
|
+
// Senpi Theme has no tree-token API; fixed ├/└/│ glyphs intentionally mirror omp.
|
|
481
|
+
for (const [index, event] of rows.entries()) {
|
|
482
|
+
const isLast = index === rows.length - 1;
|
|
483
|
+
const status = agentStatus(event["status"]);
|
|
484
|
+
const presentation = agentPresentation(status, environment.spinnerFrame);
|
|
485
|
+
const id = eventString(event["id"]) ?? "agent";
|
|
486
|
+
const styledId = environment.theme === undefined ? id : environment.theme.bold(id);
|
|
487
|
+
let body = `${style(environment.theme, presentation.color, presentation.icon)} ${styledId} ${presentation.label}`;
|
|
488
|
+
if (status === "completed" || status === "failed" || status === "aborted") {
|
|
489
|
+
const duration = eventNumber(event["durationMs"]);
|
|
490
|
+
if (duration > 0) body += ` · ${style(environment.theme, "dim", formatDuration(duration))}`;
|
|
491
|
+
}
|
|
492
|
+
const branch = isLast ? "└ " : "├ ";
|
|
493
|
+
const continuation = isLast ? " " : "│ ";
|
|
494
|
+
appendLines(
|
|
495
|
+
lines,
|
|
496
|
+
renderPrefixed(body, environment, { prefix: branch, continuation: continuation, color: "dim" }),
|
|
497
|
+
);
|
|
498
|
+
if (status !== "running") continue;
|
|
499
|
+
const currentTool = eventString(event["currentTool"]);
|
|
500
|
+
const lastIntent = eventString(event["lastIntent"]);
|
|
501
|
+
if (currentTool === undefined && lastIntent === undefined) continue;
|
|
502
|
+
const detail =
|
|
503
|
+
currentTool === undefined
|
|
504
|
+
? (lastIntent ?? "")
|
|
505
|
+
: `${currentTool}${lastIntent === undefined ? "" : `: ${lastIntent}`}`;
|
|
506
|
+
appendLines(
|
|
507
|
+
lines,
|
|
508
|
+
renderPrefixed(detail, environment, {
|
|
509
|
+
prefix: `${continuation}└ `,
|
|
510
|
+
continuation: `${continuation} `,
|
|
511
|
+
color: "dim",
|
|
512
|
+
}),
|
|
513
|
+
);
|
|
514
|
+
}
|
|
515
|
+
return lines;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
function renderCell(cell: EvalCellResult, environment: RenderEnvironment, badges: CellBadges): string[] {
|
|
519
|
+
const lines = renderPrefixed(cellHeader(cell, environment, badges), environment, {
|
|
520
|
+
prefix: "╭─ ",
|
|
521
|
+
continuation: "│ ",
|
|
522
|
+
color: "borderAccent",
|
|
523
|
+
});
|
|
524
|
+
const innerWidth = Math.max(1, environment.width - 2);
|
|
525
|
+
const codePreview = previewText(
|
|
526
|
+
highlightedCode(cell.code, cell.language, environment.theme),
|
|
527
|
+
environment.expanded ? Number.POSITIVE_INFINITY : CODE_PREVIEW_LINES,
|
|
528
|
+
innerWidth,
|
|
529
|
+
);
|
|
530
|
+
if (codePreview.skipped > 0) {
|
|
531
|
+
appendLines(
|
|
532
|
+
lines,
|
|
533
|
+
renderPrefixed(`${codePreview.skipped} earlier code lines`, environment, {
|
|
534
|
+
prefix: "│ ",
|
|
535
|
+
continuation: "│ ",
|
|
536
|
+
color: "muted",
|
|
537
|
+
}),
|
|
538
|
+
);
|
|
539
|
+
}
|
|
540
|
+
for (const line of codePreview.lines) {
|
|
541
|
+
appendLines(lines, renderPrefixed(line, environment, { prefix: "│ ", continuation: "│ ", color: "borderMuted" }));
|
|
542
|
+
}
|
|
543
|
+
const output = stripOutputNotice(cell.output, environment.meta).trimEnd();
|
|
544
|
+
if (output.length > 0) {
|
|
545
|
+
appendLines(lines, renderPrefixed("output", environment, { prefix: "├─ ", continuation: "│ ", color: "dim" }));
|
|
546
|
+
const outputColor: ThemeColor = cell.status === "error" ? "error" : "toolOutput";
|
|
547
|
+
const styledOutput = output
|
|
548
|
+
.split("\n")
|
|
549
|
+
.map((line) => style(environment.theme, outputColor, line))
|
|
550
|
+
.join("\n");
|
|
551
|
+
const outputPreview = previewText(
|
|
552
|
+
styledOutput,
|
|
553
|
+
environment.expanded ? Number.POSITIVE_INFINITY : OUTPUT_PREVIEW_LINES,
|
|
554
|
+
innerWidth,
|
|
555
|
+
);
|
|
556
|
+
if (outputPreview.skipped > 0) {
|
|
557
|
+
appendLines(
|
|
558
|
+
lines,
|
|
559
|
+
renderPrefixed(`${outputPreview.skipped} earlier output lines`, environment, {
|
|
560
|
+
prefix: "│ ",
|
|
561
|
+
continuation: "│ ",
|
|
562
|
+
color: "muted",
|
|
563
|
+
}),
|
|
564
|
+
);
|
|
565
|
+
}
|
|
566
|
+
for (const line of outputPreview.lines) {
|
|
567
|
+
appendLines(
|
|
568
|
+
lines,
|
|
569
|
+
renderPrefixed(line, environment, { prefix: "│ ", continuation: "│ ", color: "borderMuted" }),
|
|
570
|
+
);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
const allEvents = cell.statusEvents ?? [];
|
|
574
|
+
const statusEvents = allEvents.filter((event) => event.op !== "agent");
|
|
575
|
+
if (statusEvents.length > 0) {
|
|
576
|
+
appendLines(lines, renderPrefixed("status", environment, { prefix: "├─ ", continuation: "│ ", color: "dim" }));
|
|
577
|
+
for (const line of renderStatusEvents(statusEvents, environment)) {
|
|
578
|
+
appendLines(
|
|
579
|
+
lines,
|
|
580
|
+
renderPrefixed(line, environment, { prefix: "│ ", continuation: "│ ", color: "borderMuted" }),
|
|
581
|
+
);
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
lines.push(style(environment.theme, "borderMuted", "╰─"));
|
|
585
|
+
const agentEvents = allEvents.filter((event) => event.op === "agent");
|
|
586
|
+
if (agentEvents.length > 0) appendLines(lines, renderAgentProgressEvents(agentEvents, environment));
|
|
587
|
+
return lines;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
function renderJsonOutputs(values: readonly unknown[], environment: RenderEnvironment): string[] {
|
|
591
|
+
const lines: string[] = [];
|
|
592
|
+
const depth = environment.expanded ? JSON_TREE_MAX_DEPTH_EXPANDED : JSON_TREE_MAX_DEPTH_COLLAPSED;
|
|
593
|
+
const lineCap = environment.expanded ? JSON_TREE_MAX_LINES_EXPANDED : JSON_TREE_MAX_LINES_COLLAPSED;
|
|
594
|
+
const scalarLen = environment.expanded ? JSON_TREE_SCALAR_LEN_EXPANDED : JSON_TREE_SCALAR_LEN_COLLAPSED;
|
|
595
|
+
for (const [index, value] of values.entries()) {
|
|
596
|
+
appendLines(
|
|
597
|
+
lines,
|
|
598
|
+
renderAllVisualLines(style(environment.theme, "dim", `display[${index + 1}]`), environment.width),
|
|
599
|
+
);
|
|
600
|
+
const tree = renderJsonTreeLines(value, environment.theme, depth, lineCap, scalarLen);
|
|
601
|
+
for (const line of tree.lines) appendLines(lines, renderAllVisualLines(line, environment.width));
|
|
602
|
+
if (tree.truncated)
|
|
603
|
+
appendLines(lines, renderAllVisualLines(style(environment.theme, "dim", "…"), environment.width));
|
|
604
|
+
}
|
|
605
|
+
return lines;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
function renderDetailedLines(
|
|
609
|
+
details: EvalToolDetails,
|
|
610
|
+
result: AgentToolResult<EvalToolDetails>,
|
|
611
|
+
context: DetailedRenderContext,
|
|
612
|
+
): string[] {
|
|
613
|
+
const lines: string[] = [];
|
|
614
|
+
const cells = details.cells ?? [];
|
|
615
|
+
for (const [index, cell] of cells.entries()) {
|
|
616
|
+
const badges = {
|
|
617
|
+
reset: index === 0 && context.args.reset === true,
|
|
618
|
+
timeout: index === 0 ? context.args.timeout : undefined,
|
|
619
|
+
};
|
|
620
|
+
appendLines(lines, renderCell(cell, context.environment, badges));
|
|
621
|
+
if (index < cells.length - 1) lines.push("");
|
|
622
|
+
}
|
|
623
|
+
const jsonOutputs = details.jsonOutputs ?? [];
|
|
624
|
+
if (jsonOutputs.length > 0) {
|
|
625
|
+
if (lines.length > 0) lines.push("");
|
|
626
|
+
appendLines(lines, renderJsonOutputs(jsonOutputs, context.environment));
|
|
627
|
+
}
|
|
628
|
+
if (context.showImageFallback) {
|
|
629
|
+
for (const part of result.content) {
|
|
630
|
+
if (part.type !== "image") continue;
|
|
631
|
+
if (lines.length > 0) lines.push("");
|
|
632
|
+
appendLines(
|
|
633
|
+
lines,
|
|
634
|
+
renderAllVisualLines(`[image: ${sanitizeTerminalLabel(part.mimeType)}]`, context.environment.width),
|
|
635
|
+
);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
if (details.phase !== undefined)
|
|
639
|
+
appendLines(
|
|
640
|
+
lines,
|
|
641
|
+
renderAllVisualLines(
|
|
642
|
+
style(context.environment.theme, "muted", `phase ${details.phase}`),
|
|
643
|
+
context.environment.width,
|
|
644
|
+
),
|
|
645
|
+
);
|
|
646
|
+
if (details.notice !== undefined)
|
|
647
|
+
appendLines(
|
|
648
|
+
lines,
|
|
649
|
+
renderAllVisualLines(style(context.environment.theme, "dim", details.notice), context.environment.width),
|
|
650
|
+
);
|
|
651
|
+
const warning = formatTruncationWarning(details.meta) ?? (details.truncated ? "[eval output truncated]" : null);
|
|
652
|
+
if (warning !== null)
|
|
653
|
+
appendLines(
|
|
654
|
+
lines,
|
|
655
|
+
renderAllVisualLines(style(context.environment.theme, "warning", warning), context.environment.width),
|
|
656
|
+
);
|
|
657
|
+
return lines;
|
|
157
658
|
}
|
|
158
659
|
|
|
159
660
|
function textOutput(result: AgentToolResult<EvalToolDetails>, showImageFallback: boolean): string {
|
|
@@ -190,12 +691,20 @@ function resultHeader(
|
|
|
190
691
|
status: "running" | "done" | "error",
|
|
191
692
|
theme: Theme | undefined,
|
|
192
693
|
): string {
|
|
193
|
-
const title = details?.title ? ` ${details.title}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
694
|
+
const title = details?.title === undefined ? "" : ` ${details.title}`;
|
|
695
|
+
let color: ThemeColor;
|
|
696
|
+
switch (status) {
|
|
697
|
+
case "running":
|
|
698
|
+
color = "warning";
|
|
699
|
+
break;
|
|
700
|
+
case "done":
|
|
701
|
+
color = "success";
|
|
702
|
+
break;
|
|
703
|
+
case "error":
|
|
704
|
+
color = "error";
|
|
705
|
+
break;
|
|
706
|
+
}
|
|
707
|
+
return style(theme, color, `eval ${details?.language ?? "?"}${title} ${status}`);
|
|
199
708
|
}
|
|
200
709
|
|
|
201
710
|
function resultMetadata(
|
|
@@ -210,19 +719,49 @@ function resultMetadata(
|
|
|
210
719
|
return [{ kind: "text", text: style(theme, "muted", metadata.join(" | ")) }];
|
|
211
720
|
}
|
|
212
721
|
|
|
213
|
-
export function renderEvalCall(
|
|
722
|
+
export function renderEvalCall(
|
|
723
|
+
args: EvalToolInput,
|
|
724
|
+
theme: Theme | undefined,
|
|
725
|
+
context: RenderContext,
|
|
726
|
+
): EvalRenderComponent {
|
|
214
727
|
const component = componentFor(context);
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
728
|
+
if (theme === undefined && context.spinnerFrame === undefined) {
|
|
729
|
+
const title = args.title === undefined ? "" : ` ${args.title}`;
|
|
730
|
+
const reset = args.reset === true ? " reset" : "";
|
|
731
|
+
const timeout = args.timeout === undefined ? "" : ` timeout ${args.timeout}s`;
|
|
732
|
+
component.setBlocks([
|
|
733
|
+
{ kind: "text", text: style(theme, "toolTitle", `eval ${args.language}${title}${reset}${timeout}`) },
|
|
734
|
+
{
|
|
735
|
+
kind: "text",
|
|
736
|
+
text: style(theme, "mdCodeBlock", args.code.trim().length > 0 ? args.code : "..."),
|
|
737
|
+
maxVisualLines: context.expanded ? undefined : CODE_PREVIEW_LINES,
|
|
738
|
+
collapseKind: "code",
|
|
739
|
+
theme,
|
|
740
|
+
},
|
|
741
|
+
]);
|
|
742
|
+
return component;
|
|
743
|
+
}
|
|
218
744
|
component.setBlocks([
|
|
219
|
-
{ kind: "text", text: style(theme, "toolTitle", `eval ${args.language}${title}${reset}${timeout}`) },
|
|
220
745
|
{
|
|
221
|
-
kind: "
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
746
|
+
kind: "dynamic",
|
|
747
|
+
render: (width) => {
|
|
748
|
+
const environment: RenderEnvironment = {
|
|
749
|
+
expanded: context.expanded,
|
|
750
|
+
theme,
|
|
751
|
+
spinnerFrame: context.spinnerFrame,
|
|
752
|
+
width,
|
|
753
|
+
meta: undefined,
|
|
754
|
+
};
|
|
755
|
+
const cell: EvalCellResult = {
|
|
756
|
+
index: 0,
|
|
757
|
+
...(args.title === undefined ? {} : { title: args.title }),
|
|
758
|
+
code: args.code,
|
|
759
|
+
language: args.language,
|
|
760
|
+
output: "",
|
|
761
|
+
status: context.spinnerFrame === undefined ? "pending" : "running",
|
|
762
|
+
};
|
|
763
|
+
return renderCell(cell, environment, { reset: args.reset === true, timeout: args.timeout });
|
|
764
|
+
},
|
|
226
765
|
},
|
|
227
766
|
]);
|
|
228
767
|
return component;
|
|
@@ -232,22 +771,46 @@ export function renderEvalResult(
|
|
|
232
771
|
result: AgentToolResult<EvalToolDetails>,
|
|
233
772
|
options: ToolRenderResultOptions,
|
|
234
773
|
theme: Theme | undefined,
|
|
235
|
-
context:
|
|
236
|
-
):
|
|
774
|
+
context: ResultRenderContext,
|
|
775
|
+
): EvalRenderComponent {
|
|
237
776
|
const component = componentFor(context);
|
|
238
777
|
const details = result.details;
|
|
239
778
|
const expanded = options.expanded || context.expanded;
|
|
240
779
|
const imageProtocol = context.imageProtocol ?? null;
|
|
780
|
+
if (details?.cells !== undefined && details.cells.length > 0) {
|
|
781
|
+
const blocks: RenderBlock[] = [
|
|
782
|
+
{
|
|
783
|
+
kind: "dynamic",
|
|
784
|
+
render: (width) =>
|
|
785
|
+
renderDetailedLines(details, result, {
|
|
786
|
+
environment: {
|
|
787
|
+
expanded,
|
|
788
|
+
theme,
|
|
789
|
+
spinnerFrame: context.spinnerFrame,
|
|
790
|
+
width,
|
|
791
|
+
meta: details.meta,
|
|
792
|
+
},
|
|
793
|
+
args: context.args,
|
|
794
|
+
showImageFallback: context.showImages && imageProtocol === null,
|
|
795
|
+
}),
|
|
796
|
+
},
|
|
797
|
+
];
|
|
798
|
+
const calls = toolCallRows(details);
|
|
799
|
+
if (calls.length > 0) blocks.push({ kind: "blank" }, { kind: "toolCalls", calls, expanded, theme });
|
|
800
|
+
component.setBlocks(blocks);
|
|
801
|
+
return component;
|
|
802
|
+
}
|
|
241
803
|
const status = resultStatus(details, options, context.isError);
|
|
242
804
|
const blocks: RenderBlock[] = [
|
|
243
805
|
{ kind: "text", text: resultHeader(details, status, theme) },
|
|
244
806
|
...resultMetadata(details, options, theme),
|
|
245
807
|
{ kind: "blank" },
|
|
246
808
|
];
|
|
247
|
-
const
|
|
809
|
+
const rawOutput = textOutput(result, context.showImages && imageProtocol === null);
|
|
810
|
+
const output = stripOutputNotice(rawOutput, details?.meta).trimEnd();
|
|
248
811
|
const hasRenderedImage =
|
|
249
812
|
context.showImages && imageProtocol !== null && result.content.some((part) => part.type === "image");
|
|
250
|
-
if (output) {
|
|
813
|
+
if (output.length > 0) {
|
|
251
814
|
blocks.push({
|
|
252
815
|
kind: "text",
|
|
253
816
|
text: style(theme, "toolOutput", output),
|
|
@@ -255,13 +818,53 @@ export function renderEvalResult(
|
|
|
255
818
|
collapseKind: "output",
|
|
256
819
|
theme,
|
|
257
820
|
});
|
|
258
|
-
} else if (!hasRenderedImage) {
|
|
259
|
-
|
|
821
|
+
} else if (!hasRenderedImage) blocks.push({ kind: "text", text: style(theme, "muted", "(no output)") });
|
|
822
|
+
const statusEvents = details?.statusEvents ?? [];
|
|
823
|
+
const nonAgentEvents = statusEvents.filter((event) => event.op !== "agent");
|
|
824
|
+
const agentEvents = statusEvents.filter((event) => event.op === "agent");
|
|
825
|
+
if (nonAgentEvents.length > 0 || agentEvents.length > 0) {
|
|
826
|
+
blocks.push(
|
|
827
|
+
{ kind: "blank" },
|
|
828
|
+
{
|
|
829
|
+
kind: "dynamic",
|
|
830
|
+
render: (width) => {
|
|
831
|
+
const environment: RenderEnvironment = {
|
|
832
|
+
expanded,
|
|
833
|
+
theme,
|
|
834
|
+
spinnerFrame: context.spinnerFrame,
|
|
835
|
+
width,
|
|
836
|
+
meta: details?.meta,
|
|
837
|
+
};
|
|
838
|
+
return [
|
|
839
|
+
...renderStatusEvents(nonAgentEvents, environment),
|
|
840
|
+
...renderAgentProgressEvents(agentEvents, environment),
|
|
841
|
+
];
|
|
842
|
+
},
|
|
843
|
+
},
|
|
844
|
+
);
|
|
845
|
+
}
|
|
846
|
+
if ((details?.jsonOutputs?.length ?? 0) > 0) {
|
|
847
|
+
blocks.push(
|
|
848
|
+
{ kind: "blank" },
|
|
849
|
+
{
|
|
850
|
+
kind: "dynamic",
|
|
851
|
+
render: (width) =>
|
|
852
|
+
renderJsonOutputs(details?.jsonOutputs ?? [], {
|
|
853
|
+
expanded,
|
|
854
|
+
theme,
|
|
855
|
+
spinnerFrame: context.spinnerFrame,
|
|
856
|
+
width,
|
|
857
|
+
meta: details?.meta,
|
|
858
|
+
}),
|
|
859
|
+
},
|
|
860
|
+
);
|
|
260
861
|
}
|
|
261
862
|
const calls = toolCallRows(details);
|
|
262
863
|
if (calls.length > 0) blocks.push({ kind: "blank" }, { kind: "toolCalls", calls, expanded, theme });
|
|
263
|
-
if (details?.
|
|
264
|
-
blocks.push({ kind: "blank" }, { kind: "text", text: style(theme, "
|
|
864
|
+
if (details?.notice !== undefined)
|
|
865
|
+
blocks.push({ kind: "blank" }, { kind: "text", text: style(theme, "dim", details.notice) });
|
|
866
|
+
const warning = formatTruncationWarning(details?.meta) ?? (details?.truncated ? "[eval output truncated]" : null);
|
|
867
|
+
if (warning !== null) blocks.push({ kind: "blank" }, { kind: "text", text: style(theme, "warning", warning) });
|
|
265
868
|
component.setBlocks(blocks);
|
|
266
869
|
return component;
|
|
267
870
|
}
|