@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
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { parse } from "@babel/parser";
|
|
2
|
+
import type { ImportDeclaration } from "@babel/types";
|
|
3
|
+
|
|
4
|
+
const DYNAMIC_IMPORT_CALLEE =
|
|
5
|
+
'(typeof __senpi_import__ === "function" ? __senpi_import__ : (specifier, options) => import(specifier, options))';
|
|
6
|
+
|
|
7
|
+
type AstNode = {
|
|
8
|
+
readonly type: string;
|
|
9
|
+
readonly start: number;
|
|
10
|
+
readonly end: number;
|
|
11
|
+
readonly value: Readonly<Record<string, unknown>>;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
type TextEdit = {
|
|
15
|
+
readonly start: number;
|
|
16
|
+
readonly end: number;
|
|
17
|
+
readonly text: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
class UnexpectedImportSpecifierError extends Error {
|
|
21
|
+
readonly name = "UnexpectedImportSpecifierError";
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function assertNever(_value: never): never {
|
|
25
|
+
throw new UnexpectedImportSpecifierError("Unsupported import specifier");
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function isRecord(value: unknown): value is Readonly<Record<string, unknown>> {
|
|
29
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function nodeFrom(value: unknown): AstNode | undefined {
|
|
33
|
+
if (!isRecord(value)) return undefined;
|
|
34
|
+
const type = value["type"];
|
|
35
|
+
const start = value["start"];
|
|
36
|
+
const end = value["end"];
|
|
37
|
+
if (typeof type !== "string" || typeof start !== "number" || typeof end !== "number") return undefined;
|
|
38
|
+
return { type, start, end, value };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function parseProgram(code: string): ReturnType<typeof parse> | undefined {
|
|
42
|
+
try {
|
|
43
|
+
return parse(code, {
|
|
44
|
+
sourceType: "module",
|
|
45
|
+
allowAwaitOutsideFunction: true,
|
|
46
|
+
allowReturnOutsideFunction: true,
|
|
47
|
+
allowImportExportEverywhere: true,
|
|
48
|
+
allowNewTargetOutsideFunction: true,
|
|
49
|
+
allowSuperOutsideMethod: true,
|
|
50
|
+
allowUndeclaredExports: true,
|
|
51
|
+
errorRecovery: true,
|
|
52
|
+
plugins: ["typescript", "importAttributes"],
|
|
53
|
+
});
|
|
54
|
+
} catch (error) {
|
|
55
|
+
if (error instanceof SyntaxError) return undefined;
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function walkNodes(root: unknown, visit: (node: AstNode) => void): void {
|
|
61
|
+
const stack: unknown[] = [root];
|
|
62
|
+
while (stack.length > 0) {
|
|
63
|
+
const current = stack.pop();
|
|
64
|
+
if (Array.isArray(current)) {
|
|
65
|
+
for (let index = current.length - 1; index >= 0; index -= 1) stack.push(current[index]);
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (!isRecord(current)) continue;
|
|
69
|
+
const node = nodeFrom(current);
|
|
70
|
+
if (node) visit(node);
|
|
71
|
+
for (const [key, value] of Object.entries(current)) {
|
|
72
|
+
if (key === "loc" || key === "extra" || key === "range" || key.endsWith("Comments")) continue;
|
|
73
|
+
if (value !== null && typeof value === "object") stack.push(value);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function importOptions(node: ImportDeclaration): string | undefined {
|
|
79
|
+
if (!node.attributes || node.attributes.length === 0) return undefined;
|
|
80
|
+
const pairs = node.attributes.map((attribute) => {
|
|
81
|
+
const key = attribute.key.type === "Identifier" ? attribute.key.name : JSON.stringify(attribute.key.value);
|
|
82
|
+
return `${key}: ${JSON.stringify(attribute.value.value)}`;
|
|
83
|
+
});
|
|
84
|
+
return `{ with: { ${pairs.join(", ")} } }`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function importCall(source: string, options: string | undefined): string {
|
|
88
|
+
const sourceLiteral = JSON.stringify(source);
|
|
89
|
+
return options ? `__senpi_import__(${sourceLiteral}, ${options})` : `__senpi_import__(${sourceLiteral})`;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function rewriteImportDeclaration(node: ImportDeclaration): string {
|
|
93
|
+
const call = importCall(node.source.value, importOptions(node));
|
|
94
|
+
let defaultName: string | undefined;
|
|
95
|
+
let namespaceName: string | undefined;
|
|
96
|
+
const namedBindings: Array<readonly [imported: string, local: string]> = [];
|
|
97
|
+
|
|
98
|
+
for (const specifier of node.specifiers) {
|
|
99
|
+
switch (specifier.type) {
|
|
100
|
+
case "ImportDefaultSpecifier":
|
|
101
|
+
defaultName = specifier.local.name;
|
|
102
|
+
break;
|
|
103
|
+
case "ImportNamespaceSpecifier":
|
|
104
|
+
namespaceName = specifier.local.name;
|
|
105
|
+
break;
|
|
106
|
+
case "ImportSpecifier": {
|
|
107
|
+
const imported =
|
|
108
|
+
specifier.imported.type === "Identifier" ? specifier.imported.name : specifier.imported.value;
|
|
109
|
+
namedBindings.push([imported, specifier.local.name]);
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
default:
|
|
113
|
+
assertNever(specifier);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (namedBindings.length > 0) {
|
|
118
|
+
const named = namedBindings
|
|
119
|
+
.map(([imported, local]) => (imported === local ? imported : `${imported}: ${local}`))
|
|
120
|
+
.join(", ");
|
|
121
|
+
const bindings = defaultName ? `default: ${defaultName}, ${named}` : named;
|
|
122
|
+
return `const { ${bindings} } = await ${call};`;
|
|
123
|
+
}
|
|
124
|
+
if (namespaceName && defaultName) {
|
|
125
|
+
return `const ${namespaceName} = await ${call}; const ${defaultName} = ${namespaceName}.default;`;
|
|
126
|
+
}
|
|
127
|
+
if (namespaceName) return `const ${namespaceName} = await ${call};`;
|
|
128
|
+
if (defaultName) return `const ${defaultName} = (await ${call}).default;`;
|
|
129
|
+
return `await ${call};`;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function dynamicImportEdit(node: AstNode): TextEdit | undefined {
|
|
133
|
+
if (node.type !== "CallExpression") return undefined;
|
|
134
|
+
const callee = nodeFrom(node.value["callee"]);
|
|
135
|
+
if (callee?.type !== "Import") return undefined;
|
|
136
|
+
return { start: callee.start, end: callee.end, text: DYNAMIC_IMPORT_CALLEE };
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function applyEdits(code: string, edits: readonly TextEdit[]): string {
|
|
140
|
+
if (edits.length === 0) return code;
|
|
141
|
+
const descending = edits.toSorted((left, right) => right.start - left.start);
|
|
142
|
+
let output = code;
|
|
143
|
+
for (const edit of descending) {
|
|
144
|
+
output = output.slice(0, edit.start) + edit.text + output.slice(edit.end);
|
|
145
|
+
}
|
|
146
|
+
return output;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export function rewriteImports(code: string): string {
|
|
150
|
+
if (!code.includes("import")) return code;
|
|
151
|
+
const ast = parseProgram(code);
|
|
152
|
+
if (!ast) return code;
|
|
153
|
+
const edits: TextEdit[] = [];
|
|
154
|
+
|
|
155
|
+
for (const node of ast.program.body) {
|
|
156
|
+
if (node.type !== "ImportDeclaration" || typeof node.start !== "number" || typeof node.end !== "number") continue;
|
|
157
|
+
edits.push({ start: node.start, end: node.end, text: rewriteImportDeclaration(node) });
|
|
158
|
+
}
|
|
159
|
+
walkNodes(ast.program, (node) => {
|
|
160
|
+
const edit = dynamicImportEdit(node);
|
|
161
|
+
if (edit) edits.push(edit);
|
|
162
|
+
});
|
|
163
|
+
return applyEdits(code, edits);
|
|
164
|
+
}
|
|
@@ -34,7 +34,12 @@ export function createWorkerCore(transport, options) {
|
|
|
34
34
|
|
|
35
35
|
function onMessage(message) {
|
|
36
36
|
if (message.type === "init") {
|
|
37
|
-
runtime = new JsWorkerRuntime({
|
|
37
|
+
runtime = new JsWorkerRuntime({
|
|
38
|
+
cwd: options.cwd,
|
|
39
|
+
parallelPoolWidth: options.parallelPoolWidth,
|
|
40
|
+
localRoots: message.connection.localRoots,
|
|
41
|
+
artifactsDir: message.connection.artifactsDir,
|
|
42
|
+
});
|
|
38
43
|
emit({ type: "ready" });
|
|
39
44
|
return;
|
|
40
45
|
}
|
|
@@ -1,24 +1,41 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
1
|
+
// allow: SIZE_OK — private runtime state and installed globals must stay in one worker module.
|
|
2
|
+
import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
3
|
+
import { dirname, isAbsolute, join, normalize, resolve, sep } from "node:path";
|
|
3
4
|
import { inspect } from "node:util";
|
|
4
5
|
import { awaitMaybePromise, indirectEval, wrapUserCode } from "./worker-indirect-eval.js";
|
|
5
6
|
|
|
7
|
+
const PREPARED_CELL_PREFIX = "/*senpi:prepared-cell*/";
|
|
8
|
+
const INTERNAL_URL = /^([a-z][a-z0-9+.-]*):\/\/(.*)$/iu;
|
|
9
|
+
const BASE64_STRICT_RE = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/u;
|
|
10
|
+
const DECIMAL_CSV_RE = /^\d{1,3}(?:,\d{1,3})*$/u;
|
|
11
|
+
|
|
6
12
|
export class JsWorkerRuntime {
|
|
7
13
|
#cwd;
|
|
8
14
|
#parallelPoolWidth;
|
|
15
|
+
#localRoots;
|
|
9
16
|
#env = new Map();
|
|
10
17
|
#hooks = null;
|
|
11
18
|
|
|
12
19
|
constructor(options) {
|
|
13
20
|
this.#cwd = options.cwd;
|
|
14
21
|
this.#parallelPoolWidth = options.parallelPoolWidth;
|
|
22
|
+
this.#localRoots = { ...(options.localRoots ?? {}) };
|
|
23
|
+
if (options.artifactsDir && !this.#localRoots.local) this.#localRoots.local = join(options.artifactsDir, "local");
|
|
15
24
|
this.#installGlobals();
|
|
16
25
|
}
|
|
17
26
|
|
|
18
27
|
async run(code, cellId, hooks) {
|
|
19
28
|
this.#hooks = hooks;
|
|
20
29
|
try {
|
|
21
|
-
|
|
30
|
+
let prelude = "";
|
|
31
|
+
let cellCode = code;
|
|
32
|
+
if (code.startsWith(PREPARED_CELL_PREFIX)) {
|
|
33
|
+
const prepared = JSON.parse(code.slice(PREPARED_CELL_PREFIX.length));
|
|
34
|
+
if (!isPlainObject(prepared) || typeof prepared.prelude !== "string" || typeof prepared.code !== "string") throw new Error("Invalid prepared JavaScript cell payload");
|
|
35
|
+
({ prelude, code: cellCode } = prepared);
|
|
36
|
+
}
|
|
37
|
+
if (prelude) indirectEval(prelude, `${cellId}:prelude`);
|
|
38
|
+
return await awaitMaybePromise(indirectEval(wrapUserCode(cellCode), cellId));
|
|
22
39
|
} finally {
|
|
23
40
|
this.#hooks = null;
|
|
24
41
|
}
|
|
@@ -30,8 +47,10 @@ export class JsWorkerRuntime {
|
|
|
30
47
|
globalThis.log = message => this.#hooks?.emit({ type: "log", message: String(message) });
|
|
31
48
|
globalThis.phase = title => this.#hooks?.emit({ type: "phase", title: String(title) });
|
|
32
49
|
globalThis.env = (key, value) => this.#envHelper(key, value);
|
|
33
|
-
globalThis.read = async (path,
|
|
50
|
+
globalThis.read = async (path, options, ...rest) => await this.#read(path, helperOptions("read", options, rest));
|
|
34
51
|
globalThis.write = async (path, content) => await this.#write(path, content);
|
|
52
|
+
globalThis.output = async (...args) => await this.#output(args);
|
|
53
|
+
globalThis.agent = async (prompt, options, ...rest) => await this.#agent(prompt, options, rest);
|
|
35
54
|
globalThis.parallel = async thunks => await this.#parallel(thunks);
|
|
36
55
|
globalThis.pipeline = async (items, ...stages) => await this.#pipeline(items, stages);
|
|
37
56
|
globalThis.completion = async (prompt, opts) => await this.#callTool("completion", { prompt, opts });
|
|
@@ -40,21 +59,34 @@ export class JsWorkerRuntime {
|
|
|
40
59
|
{
|
|
41
60
|
get: (_target, prop) => {
|
|
42
61
|
if (typeof prop !== "string") return undefined;
|
|
43
|
-
return async args => await this.#callTool(prop, args);
|
|
62
|
+
return async args => await this.#callTool(prop, args ?? {});
|
|
44
63
|
},
|
|
45
64
|
},
|
|
46
65
|
);
|
|
47
66
|
const originalLog = console.log.bind(console);
|
|
48
67
|
const originalError = console.error.bind(console);
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
68
|
+
const originalStdoutWrite = process.stdout.write;
|
|
69
|
+
const originalStderrWrite = process.stderr.write;
|
|
70
|
+
const routeWrite = (stream, originalWrite, streamName) => {
|
|
71
|
+
const write = originalWrite.bind(stream);
|
|
72
|
+
return (chunk, encoding, callback) => {
|
|
73
|
+
if (!this.#hooks) return write(chunk, encoding, callback);
|
|
74
|
+
const callbackValue = typeof encoding === "function" ? encoding : callback;
|
|
75
|
+
const encodingValue = typeof encoding === "string" ? encoding : undefined;
|
|
76
|
+
this.#emitText(streamName, chunkToString(chunk, encodingValue));
|
|
77
|
+
if (typeof callbackValue === "function") callbackValue();
|
|
78
|
+
return true;
|
|
79
|
+
};
|
|
54
80
|
};
|
|
81
|
+
process.stdout.write = routeWrite(process.stdout, originalStdoutWrite, "stdout");
|
|
82
|
+
process.stderr.write = routeWrite(process.stderr, originalStderrWrite, "stderr");
|
|
83
|
+
console.log = (...values) => this.#emitText("stdout", `${values.map(formatValue).join(" ")}\n`);
|
|
84
|
+
console.error = (...values) => this.#emitText("stderr", `${values.map(formatValue).join(" ")}\n`);
|
|
55
85
|
globalThis.__senpi_restore_console__ = () => {
|
|
56
86
|
console.log = originalLog;
|
|
57
87
|
console.error = originalError;
|
|
88
|
+
process.stdout.write = originalStdoutWrite;
|
|
89
|
+
process.stderr.write = originalStderrWrite;
|
|
58
90
|
};
|
|
59
91
|
}
|
|
60
92
|
|
|
@@ -62,73 +94,307 @@ export class JsWorkerRuntime {
|
|
|
62
94
|
this.#hooks?.emit({ type: "text", stream, data });
|
|
63
95
|
}
|
|
64
96
|
|
|
97
|
+
#emitStatus(event) {
|
|
98
|
+
this.#hooks?.emit({ type: "status", event });
|
|
99
|
+
}
|
|
100
|
+
|
|
65
101
|
#display(value) {
|
|
66
|
-
if (value && typeof value === "object"
|
|
67
|
-
|
|
102
|
+
if (value && typeof value === "object") {
|
|
103
|
+
if (value.type === "markdown" && typeof value.text === "string") {
|
|
104
|
+
this.#hooks?.emit({ type: "display", mimeType: "text/markdown", dataBase64: encodeBase64(value.text) });
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (value.type === "image" && typeof value.mimeType === "string") {
|
|
108
|
+
const dataBase64 = imageBase64(value.data);
|
|
109
|
+
if (dataBase64 !== undefined) {
|
|
110
|
+
this.#hooks?.emit({ type: "display", mimeType: value.mimeType, dataBase64 });
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
this.#emitText(
|
|
114
|
+
"stdout",
|
|
115
|
+
`[display: image dropped — \`data\` must be a base64 string, Uint8Array/Buffer, or ArrayBuffer; got ${describeImageData(value.data)}]\n`,
|
|
116
|
+
);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (typeof value.mimeType === "string" && typeof value.dataBase64 === "string") {
|
|
120
|
+
this.#hooks?.emit({ type: "display", mimeType: value.mimeType, dataBase64: value.dataBase64 });
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
try {
|
|
124
|
+
this.#hooks?.emit({ type: "display", mimeType: "application/json", dataBase64: encodeBase64(JSON.stringify(value)) });
|
|
125
|
+
} catch (error) {
|
|
126
|
+
if (!(error instanceof TypeError)) throw error;
|
|
127
|
+
this.#emitText("stdout", `${inspect(value, { colors: false, depth: 5 })}\n`);
|
|
128
|
+
}
|
|
68
129
|
return;
|
|
69
130
|
}
|
|
70
|
-
this.#
|
|
71
|
-
type: "display",
|
|
72
|
-
mimeType: "application/json",
|
|
73
|
-
dataBase64: Buffer.from(JSON.stringify(value), "utf8").toString("base64"),
|
|
74
|
-
});
|
|
131
|
+
this.#emitText("stdout", `${String(value)}\n`);
|
|
75
132
|
}
|
|
76
133
|
|
|
77
134
|
#envHelper(key, value) {
|
|
78
|
-
if (key === undefined
|
|
135
|
+
if (key === undefined || key === null || key === "") {
|
|
136
|
+
const merged = Object.fromEntries(Object.entries({ ...process.env, ...Object.fromEntries(this.#env) }).sort());
|
|
137
|
+
this.#emitStatus({ op: "env", count: Object.keys(merged).length, keys: Object.keys(merged).slice(0, 20) });
|
|
138
|
+
return merged;
|
|
139
|
+
}
|
|
140
|
+
const name = String(key);
|
|
79
141
|
if (value !== undefined) {
|
|
80
142
|
const stringValue = String(value);
|
|
81
|
-
this.#env.set(
|
|
143
|
+
this.#env.set(name, stringValue);
|
|
144
|
+
this.#emitStatus({ op: "env", key: name, value: stringValue, action: "set" });
|
|
82
145
|
return stringValue;
|
|
83
146
|
}
|
|
84
|
-
|
|
147
|
+
const result = this.#env.get(name) ?? process.env[name];
|
|
148
|
+
this.#emitStatus({ op: "env", key: name, value: result, action: "get" });
|
|
149
|
+
return result;
|
|
85
150
|
}
|
|
86
151
|
|
|
87
|
-
async #read(rawPath,
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
152
|
+
async #read(rawPath, options) {
|
|
153
|
+
const path = this.#resolvePath(String(rawPath), "read");
|
|
154
|
+
const info = await stat(path);
|
|
155
|
+
if (info.isDirectory()) throw new Error(`Directory paths are not supported by read(): ${path}`);
|
|
156
|
+
let text = await readFile(path, "utf8");
|
|
157
|
+
const offset = typeof options.offset === "number" ? options.offset : 1;
|
|
158
|
+
const limit = typeof options.limit === "number" ? options.limit : undefined;
|
|
159
|
+
if (offset > 1 || limit !== undefined) {
|
|
160
|
+
const lines = text.split(/\r?\n/u);
|
|
161
|
+
const start = Math.max(0, offset - 1);
|
|
162
|
+
text = lines.slice(start, limit === undefined ? undefined : start + limit).join("\n");
|
|
163
|
+
}
|
|
164
|
+
this.#emitStatus({ op: "read", path, bytes: info.size, chars: text.length });
|
|
165
|
+
return text;
|
|
92
166
|
}
|
|
93
167
|
|
|
94
168
|
async #write(rawPath, content) {
|
|
95
|
-
const path = this.#resolvePath(String(rawPath));
|
|
169
|
+
const path = this.#resolvePath(String(rawPath), "write");
|
|
170
|
+
const data = await writeData(content);
|
|
96
171
|
await mkdir(dirname(path), { recursive: true });
|
|
97
|
-
await writeFile(path,
|
|
172
|
+
await writeFile(path, data);
|
|
173
|
+
this.#emitStatus({ op: "write", path, bytes: typeof data === "string" ? Buffer.byteLength(data) : data.byteLength });
|
|
174
|
+
return path;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
#resolvePath(rawPath, operation) {
|
|
178
|
+
const match = INTERNAL_URL.exec(rawPath);
|
|
179
|
+
if (!match) return isAbsolute(rawPath) ? normalize(rawPath) : resolve(this.#cwd, rawPath);
|
|
180
|
+
const scheme = match[1].toLowerCase();
|
|
181
|
+
const root = this.#localRoots[scheme];
|
|
182
|
+
if (!root) throw new Error(`Protocol paths are not supported by ${operation}(): ${rawPath}`);
|
|
183
|
+
let relative;
|
|
184
|
+
try {
|
|
185
|
+
relative = decodeURIComponent(match[2].replaceAll("\\", "/"));
|
|
186
|
+
} catch (error) {
|
|
187
|
+
if (error instanceof URIError) throw new Error(`Invalid URL encoding in ${scheme}:// path: ${rawPath}`);
|
|
188
|
+
throw error;
|
|
189
|
+
}
|
|
190
|
+
if (isAbsolute(relative) || relative.split("/").includes("..")) {
|
|
191
|
+
throw new Error(`Path traversal is not allowed in ${scheme}:// URLs: ${rawPath}`);
|
|
192
|
+
}
|
|
193
|
+
const rootPath = resolve(root);
|
|
194
|
+
const path = resolve(rootPath, relative);
|
|
195
|
+
if (path !== rootPath && !path.startsWith(`${rootPath}${sep}`)) throw new Error(`${scheme}:// path escapes its root`);
|
|
98
196
|
return path;
|
|
99
197
|
}
|
|
100
198
|
|
|
101
|
-
#
|
|
102
|
-
|
|
199
|
+
async #output(args) {
|
|
200
|
+
let ids = args;
|
|
201
|
+
let options = {};
|
|
202
|
+
const last = args.at(-1);
|
|
203
|
+
if (isPlainObject(last)) {
|
|
204
|
+
ids = args.slice(0, -1);
|
|
205
|
+
options = last;
|
|
206
|
+
}
|
|
207
|
+
return await this.#callTool(reservedTool("__senpi_reserved_output_tool__", "output"), {
|
|
208
|
+
ids: ids.map(String),
|
|
209
|
+
...options,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async #agent(prompt, options, rest) {
|
|
214
|
+
const parsed = optionsArg({
|
|
215
|
+
name: "agent",
|
|
216
|
+
value: options,
|
|
217
|
+
rest,
|
|
218
|
+
keys: ["agent", "model", "label", "schema", "isolated", "apply", "merge"],
|
|
219
|
+
example: "{ agent, model, label, schema, isolated, apply, merge, handle }",
|
|
220
|
+
});
|
|
221
|
+
const { handle, ...callArgs } = parsed;
|
|
222
|
+
const response = await this.#callTool(reservedTool("__senpi_reserved_agent_tool__", "agent"), {
|
|
223
|
+
prompt: String(prompt),
|
|
224
|
+
...callArgs,
|
|
225
|
+
handle: Boolean(handle),
|
|
226
|
+
});
|
|
227
|
+
const responseRecord = isPlainObject(response) ? response : {};
|
|
228
|
+
const text = Object.hasOwn(responseRecord, "text") ? responseRecord.text : response;
|
|
229
|
+
const output = Object.hasOwn(callArgs, "schema")
|
|
230
|
+
? Object.hasOwn(responseRecord, "data")
|
|
231
|
+
? responseRecord.data
|
|
232
|
+
: JSON.parse(String(text))
|
|
233
|
+
: text;
|
|
234
|
+
if (!handle) return output;
|
|
235
|
+
const details = isPlainObject(responseRecord.details) ? responseRecord.details : responseRecord;
|
|
236
|
+
const id = details.id;
|
|
237
|
+
if (id === undefined || id === null) return { text, output: text, handle: null, id: null, agent: null };
|
|
238
|
+
const node = {
|
|
239
|
+
text,
|
|
240
|
+
output: text,
|
|
241
|
+
handle: details.handle ?? `agent://${id}`,
|
|
242
|
+
id,
|
|
243
|
+
agent: details.agent ?? callArgs.agent ?? null,
|
|
244
|
+
};
|
|
245
|
+
if (Object.hasOwn(callArgs, "schema")) node.data = output;
|
|
246
|
+
for (const key of ["isolated", "patchPath", "branchName", "nestedPatches", "changesApplied", "isolationSummary"]) {
|
|
247
|
+
if (details[key] !== undefined) node[key] = details[key];
|
|
248
|
+
}
|
|
249
|
+
return node;
|
|
103
250
|
}
|
|
104
251
|
|
|
105
252
|
async #callTool(toolName, args) {
|
|
106
|
-
|
|
107
|
-
|
|
253
|
+
const hooks = this.#hooks;
|
|
254
|
+
if (!hooks) throw new Error("tool call outside active JS cell");
|
|
255
|
+
if (
|
|
256
|
+
typeof globalThis.__senpi_timeout_pause_op__ !== "string" ||
|
|
257
|
+
typeof globalThis.__senpi_timeout_resume_op__ !== "string"
|
|
258
|
+
) {
|
|
259
|
+
throw new Error("timeout bridge is unavailable");
|
|
260
|
+
}
|
|
261
|
+
this.#emitStatus({ op: globalThis.__senpi_timeout_pause_op__ });
|
|
262
|
+
try {
|
|
263
|
+
return await hooks.callTool(toolName, args);
|
|
264
|
+
} finally {
|
|
265
|
+
this.#emitStatus({ op: globalThis.__senpi_timeout_resume_op__ });
|
|
266
|
+
}
|
|
108
267
|
}
|
|
109
268
|
|
|
110
269
|
async #parallel(thunks) {
|
|
111
|
-
const
|
|
270
|
+
const list = Array.from(thunks ?? []);
|
|
271
|
+
if (list.length === 0) return [];
|
|
272
|
+
const configuredWidth = Number.isFinite(this.#parallelPoolWidth) ? Math.trunc(this.#parallelPoolWidth) : 1;
|
|
273
|
+
const workerCount = Math.min(Math.max(1, configuredWidth), list.length);
|
|
274
|
+
const results = new Array(list.length);
|
|
112
275
|
let next = 0;
|
|
113
|
-
|
|
114
|
-
|
|
276
|
+
let firstError;
|
|
277
|
+
let firstErrorIndex = list.length;
|
|
278
|
+
let hasError = false;
|
|
279
|
+
const worker = async () => {
|
|
280
|
+
while (true) {
|
|
115
281
|
const index = next;
|
|
116
282
|
next += 1;
|
|
117
|
-
|
|
283
|
+
if (index >= list.length) return;
|
|
284
|
+
try {
|
|
285
|
+
const thunk = list[index];
|
|
286
|
+
if (typeof thunk !== "function") throw new TypeError("parallel() expects an iterable of functions");
|
|
287
|
+
results[index] = await thunk(index);
|
|
288
|
+
} catch (error) {
|
|
289
|
+
if (!hasError || index < firstErrorIndex) {
|
|
290
|
+
hasError = true;
|
|
291
|
+
firstErrorIndex = index;
|
|
292
|
+
firstError = error;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
118
295
|
}
|
|
119
|
-
}
|
|
120
|
-
await Promise.all(
|
|
296
|
+
};
|
|
297
|
+
await Promise.all(Array.from({ length: workerCount }, worker));
|
|
298
|
+
if (hasError) throw firstError;
|
|
121
299
|
return results;
|
|
122
300
|
}
|
|
123
301
|
|
|
124
302
|
async #pipeline(items, stages) {
|
|
125
|
-
let current = items;
|
|
126
|
-
for (const stage of stages)
|
|
303
|
+
let current = Array.from(items ?? []);
|
|
304
|
+
for (const stage of stages) {
|
|
305
|
+
if (typeof stage !== "function") throw new TypeError("pipeline() stages must be functions");
|
|
306
|
+
current = await this.#parallel(current.map(item => async () => await stage(item)));
|
|
307
|
+
}
|
|
127
308
|
return current;
|
|
128
309
|
}
|
|
129
310
|
}
|
|
130
311
|
|
|
312
|
+
function isPlainObject(value) {
|
|
313
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function optionsArg(options) {
|
|
317
|
+
const { name, value, rest, keys, example } = options;
|
|
318
|
+
if (isPlainObject(value)) {
|
|
319
|
+
if (rest.some(item => item !== undefined && item !== null)) throw new TypeError(`${name}() options cannot mix object and positional forms`);
|
|
320
|
+
return value;
|
|
321
|
+
}
|
|
322
|
+
const values = [value, ...rest];
|
|
323
|
+
for (let index = keys.length; index < values.length; index += 1) {
|
|
324
|
+
if (values[index] !== undefined && values[index] !== null) throw new TypeError(`${name}() accepts ${example}`);
|
|
325
|
+
}
|
|
326
|
+
return Object.fromEntries(keys.flatMap((key, index) => values[index] === undefined || values[index] === null ? [] : [[key, values[index]]]));
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function helperOptions(name, value, rest) {
|
|
330
|
+
return optionsArg({ name, value, rest, keys: ["offset", "limit"], example: "{ offset, limit }" });
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
function reservedTool(globalName, helperName) {
|
|
334
|
+
const value = globalThis[globalName];
|
|
335
|
+
if (typeof value !== "string") throw new Error(`${helperName}() bridge is unavailable`);
|
|
336
|
+
return value;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
async function writeData(value) {
|
|
340
|
+
if (typeof value === "string" || value instanceof Uint8Array) return value;
|
|
341
|
+
if (value instanceof Blob) return new Uint8Array(await value.arrayBuffer());
|
|
342
|
+
if (value instanceof ArrayBuffer) return new Uint8Array(value);
|
|
343
|
+
if (ArrayBuffer.isView(value)) return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
|
|
344
|
+
throw new TypeError("write() expects string, Blob, ArrayBuffer, or TypedArray data");
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function imageBase64(data) {
|
|
348
|
+
if (typeof data === "string") {
|
|
349
|
+
if (isStrictBase64(data)) return data;
|
|
350
|
+
if (!DECIMAL_CSV_RE.test(data)) return undefined;
|
|
351
|
+
const parts = data.split(",");
|
|
352
|
+
const bytes = new Uint8Array(parts.length);
|
|
353
|
+
for (let index = 0; index < parts.length; index += 1) {
|
|
354
|
+
const byte = Number(parts[index]);
|
|
355
|
+
if (!Number.isInteger(byte) || byte < 0 || byte > 255) return undefined;
|
|
356
|
+
bytes[index] = byte;
|
|
357
|
+
}
|
|
358
|
+
return Buffer.from(bytes).toString("base64");
|
|
359
|
+
}
|
|
360
|
+
if (data instanceof Uint8Array) return Buffer.from(data).toString("base64");
|
|
361
|
+
if (data instanceof ArrayBuffer) return Buffer.from(data).toString("base64");
|
|
362
|
+
if (ArrayBuffer.isView(data)) return Buffer.from(data.buffer, data.byteOffset, data.byteLength).toString("base64");
|
|
363
|
+
if (isPlainObject(data) && data.type === "Buffer" && Array.isArray(data.data)) {
|
|
364
|
+
const bytes = new Uint8Array(data.data.length);
|
|
365
|
+
for (let index = 0; index < data.data.length; index += 1) {
|
|
366
|
+
const byte = data.data[index];
|
|
367
|
+
if (typeof byte !== "number" || !Number.isInteger(byte) || byte < 0 || byte > 255) return undefined;
|
|
368
|
+
bytes[index] = byte;
|
|
369
|
+
}
|
|
370
|
+
return Buffer.from(bytes).toString("base64");
|
|
371
|
+
}
|
|
372
|
+
return undefined;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
function isStrictBase64(value) {
|
|
376
|
+
return value.length > 0 && value.length % 4 === 0 && BASE64_STRICT_RE.test(value);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
function describeImageData(data) {
|
|
380
|
+
if (data === null) return "null";
|
|
381
|
+
if (data instanceof Uint8Array) return "Uint8Array";
|
|
382
|
+
if (data instanceof ArrayBuffer) return "ArrayBuffer";
|
|
383
|
+
if (ArrayBuffer.isView(data)) return data.constructor.name;
|
|
384
|
+
if (typeof data === "string") return `string(${data.length})`;
|
|
385
|
+
return typeof data;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
function chunkToString(chunk, encoding) {
|
|
389
|
+
if (typeof chunk === "string") return chunk;
|
|
390
|
+
if (chunk instanceof Uint8Array) return Buffer.from(chunk).toString(encoding ?? "utf8");
|
|
391
|
+
return String(chunk);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function encodeBase64(value) {
|
|
395
|
+
return Buffer.from(value, "utf8").toString("base64");
|
|
396
|
+
}
|
|
397
|
+
|
|
131
398
|
function formatValue(value) {
|
|
132
|
-
|
|
133
|
-
return inspect(value, { colors: false, depth: 5 });
|
|
399
|
+
return typeof value === "string" ? value : inspect(value, { colors: false, depth: 5 });
|
|
134
400
|
}
|
|
@@ -135,8 +135,9 @@ export class PythonKernel {
|
|
|
135
135
|
if (!pending || !this.#pending.has(pending.input.cellId)) return;
|
|
136
136
|
this.#active = pending;
|
|
137
137
|
pending.startedAt = performance.now();
|
|
138
|
-
const timeoutMs = pending.input.timeoutMs
|
|
139
|
-
|
|
138
|
+
const timeoutMs = pending.input.timeoutMs;
|
|
139
|
+
if (timeoutMs !== undefined)
|
|
140
|
+
pending.timeoutTimer = setTimeout(() => this.#timeoutRun(pending, timeoutMs), timeoutMs);
|
|
140
141
|
try {
|
|
141
142
|
this.#transport?.run(pending.input);
|
|
142
143
|
} catch (error) {
|