@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,26 +1,59 @@
|
|
|
1
1
|
import type { ExtensionContext } from "@code-yeongyu/senpi";
|
|
2
2
|
import type { KernelToHostMessage } from "./bridge/protocol.ts";
|
|
3
|
+
import type { AgentExecuteTool } from "./bridges/agent-bridge.ts";
|
|
3
4
|
import { type CompletionRequest, type CompletionResult, createCompletionHandler } from "./completion/handler.ts";
|
|
4
|
-
import { type CodemodeSettings, loadCodemodeSettings } from "./config/settings.ts";
|
|
5
5
|
import {
|
|
6
|
+
type CodemodeSettings,
|
|
7
|
+
defaultCodemodeSettings,
|
|
8
|
+
loadCodemodeSettings,
|
|
9
|
+
type ResolvedCodemodeSettings,
|
|
10
|
+
resolveEnabledLanguages,
|
|
11
|
+
} from "./config/settings.ts";
|
|
12
|
+
import {
|
|
13
|
+
CodemodeSessionDisposedError,
|
|
6
14
|
type CodemodeSessionManager,
|
|
7
15
|
type CreateCodemodeSessionManagerOptions,
|
|
8
16
|
createCodemodeSessionManager,
|
|
17
|
+
type EvalExecutionTracker,
|
|
9
18
|
} from "./extension/session-manager.ts";
|
|
10
19
|
import {
|
|
11
20
|
createInterpreterDetector,
|
|
12
21
|
getInterpreterAvailability,
|
|
13
22
|
type InterpreterAvailability,
|
|
14
23
|
} from "./interpreters/detect.ts";
|
|
24
|
+
import { resolveSessionArtifactsDir } from "./output/streaming-output.ts";
|
|
15
25
|
import { createEvalTool } from "./tool/eval-tool.ts";
|
|
16
|
-
import
|
|
26
|
+
import { renderEvalCall, renderEvalResult } from "./tool/render.ts";
|
|
27
|
+
import type { EnabledEvalLanguages, EvalKernel, EvalLanguage } from "./tool/types.ts";
|
|
28
|
+
|
|
29
|
+
const SESSION_LIFECYCLE_EVENTS = [
|
|
30
|
+
"session_start",
|
|
31
|
+
"session_shutdown",
|
|
32
|
+
"session_before_switch",
|
|
33
|
+
"session_before_fork",
|
|
34
|
+
] as const;
|
|
35
|
+
|
|
36
|
+
type SessionLifecycleEvent = (typeof SESSION_LIFECYCLE_EVENTS)[number];
|
|
37
|
+
|
|
38
|
+
type TrackedExecution = {
|
|
39
|
+
readonly promise: Promise<unknown>;
|
|
40
|
+
readonly controller: AbortController;
|
|
41
|
+
};
|
|
17
42
|
|
|
18
|
-
type
|
|
43
|
+
type SessionRuntime = {
|
|
44
|
+
readonly manager: CodemodeSessionManager;
|
|
45
|
+
readonly enabledLanguages: EnabledEvalLanguages;
|
|
46
|
+
readonly settings: ResolvedCodemodeSettings;
|
|
47
|
+
readonly artifactsDir: string;
|
|
48
|
+
readonly executeTool: AgentExecuteTool;
|
|
49
|
+
readonly spawns: boolean;
|
|
50
|
+
};
|
|
19
51
|
|
|
20
52
|
export interface CodemodeExtensionAPI {
|
|
21
53
|
registerTool(tool: ReturnType<typeof createEvalTool>): void;
|
|
22
54
|
on(event: SessionLifecycleEvent, handler: (event: unknown, ctx: ExtensionContext) => Promise<void> | void): void;
|
|
23
|
-
executeTool:
|
|
55
|
+
executeTool: AgentExecuteTool;
|
|
56
|
+
getActiveTools(): string[];
|
|
24
57
|
}
|
|
25
58
|
|
|
26
59
|
export interface SenpiCodemodeOptions {
|
|
@@ -30,60 +63,122 @@ export interface SenpiCodemodeOptions {
|
|
|
30
63
|
readonly complete?: (request: CompletionRequest, ctx: ExtensionContext) => Promise<CompletionResult>;
|
|
31
64
|
}
|
|
32
65
|
|
|
66
|
+
class CodemodeSessionNotStartedError extends Error {
|
|
67
|
+
readonly name = "CodemodeSessionNotStartedError";
|
|
68
|
+
|
|
69
|
+
constructor() {
|
|
70
|
+
super("codemode session has not started");
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
33
74
|
export default function senpiCodemode(pi: CodemodeExtensionAPI, options: SenpiCodemodeOptions = {}): void {
|
|
34
75
|
const manager = new SessionManagerProxy();
|
|
35
76
|
const complete = options.complete ?? ((request, ctx) => createCompletionHandler()(ctx)(request));
|
|
77
|
+
const renderers = { renderCall: renderEvalCall, renderResult: renderEvalResult };
|
|
36
78
|
pi.registerTool(
|
|
37
79
|
createEvalTool({
|
|
38
80
|
enabledLanguages: { py: true, js: true, rb: true, jl: true },
|
|
39
81
|
kernelManager: manager,
|
|
40
|
-
cellTimeoutSeconds:
|
|
41
|
-
executeTool: (
|
|
82
|
+
cellTimeoutSeconds: defaultCodemodeSettings.cellTimeoutSeconds,
|
|
83
|
+
executeTool: createExecuteTool(pi),
|
|
42
84
|
complete,
|
|
85
|
+
settings: defaultCodemodeSettings,
|
|
86
|
+
executionTracker: manager,
|
|
87
|
+
renderers,
|
|
43
88
|
}),
|
|
44
89
|
);
|
|
45
90
|
|
|
46
91
|
pi.on("session_start", async (event, ctx) => {
|
|
47
92
|
const generation = manager.beginReplacement();
|
|
48
|
-
|
|
93
|
+
const runtime = await createRuntime(pi, ctx, event, complete, options);
|
|
94
|
+
if (!(await manager.replace(generation, runtime.manager))) return;
|
|
95
|
+
pi.registerTool(
|
|
96
|
+
createEvalTool({
|
|
97
|
+
enabledLanguages: runtime.enabledLanguages,
|
|
98
|
+
kernelManager: manager,
|
|
99
|
+
cellTimeoutSeconds: runtime.settings.cellTimeoutSeconds,
|
|
100
|
+
executeTool: runtime.executeTool,
|
|
101
|
+
complete,
|
|
102
|
+
settings: runtime.settings,
|
|
103
|
+
artifactsDir: runtime.artifactsDir,
|
|
104
|
+
executionTracker: manager,
|
|
105
|
+
renderers,
|
|
106
|
+
spawns: runtime.spawns,
|
|
107
|
+
spawnDefaultAgent: runtime.settings.taskTools.task,
|
|
108
|
+
}),
|
|
109
|
+
);
|
|
49
110
|
});
|
|
50
111
|
pi.on("session_shutdown", async () => manager.dispose());
|
|
51
112
|
pi.on("session_before_switch", async () => manager.dispose());
|
|
52
113
|
pi.on("session_before_fork", async () => manager.dispose());
|
|
53
114
|
}
|
|
54
115
|
|
|
55
|
-
class SessionManagerProxy implements CodemodeSessionManager {
|
|
116
|
+
class SessionManagerProxy implements CodemodeSessionManager, EvalExecutionTracker {
|
|
56
117
|
#current: CodemodeSessionManager | undefined;
|
|
57
118
|
#generation = 0;
|
|
119
|
+
#started = false;
|
|
120
|
+
#acceptingExecutions = false;
|
|
121
|
+
readonly #executions = new Set<TrackedExecution>();
|
|
58
122
|
|
|
59
123
|
beginReplacement(): number {
|
|
60
124
|
this.#generation++;
|
|
125
|
+
this.#acceptingExecutions = false;
|
|
126
|
+
this.#abortExecutions();
|
|
61
127
|
return this.#generation;
|
|
62
128
|
}
|
|
63
129
|
|
|
64
|
-
async replace(generation: number, next: CodemodeSessionManager): Promise<
|
|
130
|
+
async replace(generation: number, next: CodemodeSessionManager): Promise<boolean> {
|
|
131
|
+
if (generation !== this.#generation) {
|
|
132
|
+
await next.dispose();
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
await this.#settleExecutions();
|
|
65
136
|
if (generation !== this.#generation) {
|
|
66
137
|
await next.dispose();
|
|
67
|
-
return;
|
|
138
|
+
return false;
|
|
68
139
|
}
|
|
69
140
|
const current = this.#current;
|
|
70
141
|
this.#current = undefined;
|
|
71
142
|
await current?.dispose();
|
|
72
143
|
if (generation !== this.#generation) {
|
|
73
144
|
await next.dispose();
|
|
74
|
-
return;
|
|
145
|
+
return false;
|
|
75
146
|
}
|
|
76
147
|
this.#current = next;
|
|
148
|
+
this.#started = true;
|
|
149
|
+
this.#acceptingExecutions = true;
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
assertEvalExecutionAllowed(): void {
|
|
154
|
+
if (this.#acceptingExecutions && this.#current !== undefined) return;
|
|
155
|
+
if (this.#started) throw new CodemodeSessionDisposedError();
|
|
156
|
+
throw new CodemodeSessionNotStartedError();
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async trackEvalExecution<Result>(execution: Promise<Result>, controller: AbortController): Promise<Result> {
|
|
160
|
+
this.assertEvalExecutionAllowed();
|
|
161
|
+
const tracked: TrackedExecution = { promise: execution, controller };
|
|
162
|
+
this.#executions.add(tracked);
|
|
163
|
+
try {
|
|
164
|
+
return await execution;
|
|
165
|
+
} finally {
|
|
166
|
+
this.#executions.delete(tracked);
|
|
167
|
+
}
|
|
77
168
|
}
|
|
78
169
|
|
|
79
170
|
async getKernel(language: EvalLanguage, onMessage: (message: KernelToHostMessage) => void): Promise<EvalKernel> {
|
|
80
|
-
|
|
81
|
-
|
|
171
|
+
this.assertEvalExecutionAllowed();
|
|
172
|
+
const current = this.#current;
|
|
173
|
+
if (current === undefined) throw new CodemodeSessionNotStartedError();
|
|
174
|
+
return await current.getKernel(language, onMessage);
|
|
82
175
|
}
|
|
83
176
|
|
|
84
177
|
async complete(request: CompletionRequest, ctx: ExtensionContext): Promise<CompletionResult> {
|
|
85
|
-
|
|
86
|
-
|
|
178
|
+
this.assertEvalExecutionAllowed();
|
|
179
|
+
const current = this.#current;
|
|
180
|
+
if (current === undefined) throw new CodemodeSessionNotStartedError();
|
|
181
|
+
return await current.complete(request, ctx);
|
|
87
182
|
}
|
|
88
183
|
|
|
89
184
|
setContext(ctx: ExtensionContext): void {
|
|
@@ -92,30 +187,69 @@ class SessionManagerProxy implements CodemodeSessionManager {
|
|
|
92
187
|
|
|
93
188
|
async dispose(): Promise<void> {
|
|
94
189
|
this.#generation++;
|
|
190
|
+
this.#acceptingExecutions = false;
|
|
191
|
+
this.#abortExecutions();
|
|
192
|
+
await this.#settleExecutions();
|
|
95
193
|
const current = this.#current;
|
|
96
194
|
this.#current = undefined;
|
|
97
195
|
await current?.dispose();
|
|
98
196
|
}
|
|
197
|
+
|
|
198
|
+
#abortExecutions(): void {
|
|
199
|
+
if (this.#executions.size === 0) return;
|
|
200
|
+
const error = new CodemodeSessionDisposedError();
|
|
201
|
+
for (const execution of this.#executions) execution.controller.abort(error);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async #settleExecutions(): Promise<void> {
|
|
205
|
+
if (this.#executions.size === 0) return;
|
|
206
|
+
await Promise.allSettled([...this.#executions].map((execution) => execution.promise));
|
|
207
|
+
}
|
|
99
208
|
}
|
|
100
209
|
|
|
101
|
-
async function
|
|
210
|
+
async function createRuntime(
|
|
102
211
|
pi: CodemodeExtensionAPI,
|
|
103
212
|
ctx: ExtensionContext,
|
|
104
213
|
event: unknown,
|
|
105
214
|
complete: (request: CompletionRequest, ctx: ExtensionContext) => Promise<CompletionResult>,
|
|
106
215
|
options: SenpiCodemodeOptions,
|
|
107
|
-
): Promise<
|
|
216
|
+
): Promise<SessionRuntime> {
|
|
108
217
|
const loaded = await loadCodemodeSettings({ cwd: ctx.cwd });
|
|
109
|
-
const
|
|
218
|
+
const settings: ResolvedCodemodeSettings = {
|
|
219
|
+
...loaded.settings,
|
|
220
|
+
languages: resolveEnabledLanguages(loaded.settings),
|
|
221
|
+
};
|
|
222
|
+
const availability = await getInterpreterAvailability(settings, createInterpreterDetector());
|
|
223
|
+
const enabledLanguages = enabledLanguagesFrom(settings, availability);
|
|
224
|
+
const artifacts = resolveSessionArtifactsDir(ctx.sessionManager.getSessionFile());
|
|
225
|
+
const activeTools = new Set(pi.getActiveTools());
|
|
226
|
+
const executeTool = createExecuteTool(pi, activeTools);
|
|
110
227
|
const create = options.createSessionManager ?? createCodemodeSessionManager;
|
|
111
|
-
|
|
228
|
+
const manager = await create({
|
|
112
229
|
sessionId: sessionIdFrom(event),
|
|
113
230
|
cwd: ctx.cwd,
|
|
114
|
-
settings
|
|
231
|
+
settings,
|
|
115
232
|
availability,
|
|
116
|
-
|
|
233
|
+
artifactsDir: artifacts.dir,
|
|
234
|
+
executeTool,
|
|
117
235
|
complete,
|
|
118
236
|
});
|
|
237
|
+
return {
|
|
238
|
+
manager,
|
|
239
|
+
enabledLanguages,
|
|
240
|
+
settings,
|
|
241
|
+
artifactsDir: artifacts.dir,
|
|
242
|
+
executeTool,
|
|
243
|
+
spawns: activeTools.has(settings.taskTools.task),
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function createExecuteTool(pi: CodemodeExtensionAPI, activeTools?: ReadonlySet<string>): AgentExecuteTool {
|
|
248
|
+
const executeTool: AgentExecuteTool = (toolName, params, executeOptions) =>
|
|
249
|
+
pi.executeTool(toolName, params, executeOptions);
|
|
250
|
+
return Object.assign(executeTool, {
|
|
251
|
+
isToolAvailable: (name: string): boolean => activeTools?.has(name) ?? pi.getActiveTools().includes(name),
|
|
252
|
+
});
|
|
119
253
|
}
|
|
120
254
|
|
|
121
255
|
function sessionIdFrom(event: unknown): string {
|
|
@@ -144,7 +144,7 @@ function candidateInvocation(candidate: string): { readonly command: string; rea
|
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
function parseVersion(output: string): string | null {
|
|
147
|
-
const match = /(?:Python|ruby|julia)\s+v?(\d+(?:\.\d+){1,3})/i.exec(output.trim());
|
|
147
|
+
const match = /(?:Python|ruby|julia)\s+(?:version\s+)?v?(\d+(?:\.\d+){1,3})/i.exec(output.trim());
|
|
148
148
|
return match?.[1] ?? null;
|
|
149
149
|
}
|
|
150
150
|
|
|
@@ -1,79 +1,283 @@
|
|
|
1
|
-
#
|
|
2
|
-
# home) the first `using Base64` triggers a serial package precompile (~1s+ of CPU
|
|
3
|
-
# and disk IO); under an oversubscribed CI runner that spike balloons past the
|
|
4
|
-
# per-cell timeout, so the kernel's first cell would flakily time out, restart, and
|
|
5
|
-
# lose session state. Every other kernel dependency (Sockets in runner.jl, Base) is
|
|
6
|
-
# already in the shipped sysimage and needs no precompile, so base64 is the only
|
|
7
|
-
# precompile trigger — we hand-roll it against Base to keep cold start deterministic.
|
|
8
|
-
# Verified byte-exact against Base64.base64encode (empty / 1-2-3 byte remainders /
|
|
9
|
-
# multibyte UTF-8 / binary / long input).
|
|
1
|
+
# allow: SIZE_OK — this dependency-free kernel prelude is loaded as one runtime asset.
|
|
10
2
|
const SENPI_B64_ALPHABET = collect("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")
|
|
11
3
|
|
|
12
4
|
function senpi_base64(text::AbstractString)
|
|
13
|
-
# prelude.jl shadows Base `write` within Main, so infrastructure must qualify
|
|
14
|
-
# Base.write explicitly (see the same policy note in runner.jl).
|
|
15
5
|
bytes = codeunits(text)
|
|
16
6
|
out = IOBuffer()
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
Base.write(out, SENPI_B64_ALPHABET[(
|
|
24
|
-
Base.write(out, SENPI_B64_ALPHABET[(((
|
|
25
|
-
Base.write(out,
|
|
26
|
-
|
|
27
|
-
i += 3
|
|
7
|
+
index = 1
|
|
8
|
+
while index <= length(bytes)
|
|
9
|
+
first_byte = bytes[index]
|
|
10
|
+
second_byte = index + 1 <= length(bytes) ? bytes[index + 1] : UInt8(0)
|
|
11
|
+
third_byte = index + 2 <= length(bytes) ? bytes[index + 2] : UInt8(0)
|
|
12
|
+
Base.write(out, SENPI_B64_ALPHABET[(first_byte >> 2) + 1])
|
|
13
|
+
Base.write(out, SENPI_B64_ALPHABET[(((first_byte & 0x03) << 4) | (second_byte >> 4)) + 1])
|
|
14
|
+
Base.write(out, index + 1 <= length(bytes) ? SENPI_B64_ALPHABET[(((second_byte & 0x0f) << 2) | (third_byte >> 6)) + 1] : '=')
|
|
15
|
+
Base.write(out, index + 2 <= length(bytes) ? SENPI_B64_ALPHABET[(third_byte & 0x3f) + 1] : '=')
|
|
16
|
+
index += 3
|
|
28
17
|
end
|
|
29
|
-
|
|
18
|
+
String(take!(out))
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
function senpi_status_events_enabled()
|
|
22
|
+
get(senpi_connection, "statusEvents", true) !== false
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
function senpi_emit_status(op::AbstractString, fields::AbstractDict=Dict{String, Any}(); force::Bool=false)
|
|
26
|
+
(force || senpi_status_events_enabled()) || return nothing
|
|
27
|
+
event = Dict{String, Any}("op" => string(op))
|
|
28
|
+
for (key, value) in fields
|
|
29
|
+
event[string(key)] = value
|
|
30
|
+
end
|
|
31
|
+
senpi_emit(Dict("type" => "status", "event" => event))
|
|
32
|
+
nothing
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
function senpi_with_bridge_timeout_pause(operation::Function)
|
|
36
|
+
senpi_emit_status("timeout-pause"; force=true)
|
|
37
|
+
try
|
|
38
|
+
return operation()
|
|
39
|
+
finally
|
|
40
|
+
senpi_emit_status("timeout-resume"; force=true)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
function senpi_url_decode(value::AbstractString)
|
|
45
|
+
out = IOBuffer()
|
|
46
|
+
index = 1
|
|
47
|
+
while index <= ncodeunits(value)
|
|
48
|
+
character = Char(codeunit(value, index))
|
|
49
|
+
if character == '%' && index + 2 <= ncodeunits(value)
|
|
50
|
+
hex = value[index + 1:index + 2]
|
|
51
|
+
parsed = tryparse(UInt8, hex; base=16)
|
|
52
|
+
if parsed !== nothing
|
|
53
|
+
Base.write(out, parsed)
|
|
54
|
+
index += 3
|
|
55
|
+
continue
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
Base.write(out, character)
|
|
59
|
+
index += 1
|
|
60
|
+
end
|
|
61
|
+
String(take!(out))
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
function senpi_resolve_path(value::AbstractString)
|
|
65
|
+
raw = string(value)
|
|
66
|
+
matched = match(r"^([a-z][a-z0-9+.\-]*)://(.*)$"i, raw)
|
|
67
|
+
matched === nothing && return abspath(raw)
|
|
68
|
+
scheme = lowercase(string(matched.captures[1]))
|
|
69
|
+
roots = get(senpi_connection, "localRoots", nothing)
|
|
70
|
+
root = roots isa AbstractDict ? get(roots, scheme, nothing) : nothing
|
|
71
|
+
root isa AbstractString && !isempty(root) || error("Protocol paths are not supported by this helper: $raw")
|
|
72
|
+
relative = senpi_url_decode(replace(string(matched.captures[2]), '\\' => '/'))
|
|
73
|
+
root_path = abspath(string(root))
|
|
74
|
+
isempty(relative) && return root_path
|
|
75
|
+
(startswith(relative, '/') || ".." in split(relative, '/')) && error("Unsafe $scheme:// path (absolute or traversal): $raw")
|
|
76
|
+
resolved = abspath(joinpath(root_path, relative))
|
|
77
|
+
(resolved == root_path || startswith(resolved, root_path * string(Base.Filesystem.path_separator))) || error("$scheme:// path escapes its root: $raw")
|
|
78
|
+
resolved
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
function senpi_display_payload(value)
|
|
82
|
+
if value isa AbstractDict
|
|
83
|
+
kind = get(value, "type", get(value, :type, nothing))
|
|
84
|
+
text_value = get(value, "text", get(value, :text, nothing))
|
|
85
|
+
if kind == "markdown" && text_value !== nothing
|
|
86
|
+
return "text/markdown", string(text_value), false
|
|
87
|
+
end
|
|
88
|
+
mime_type = get(value, "mimeType", get(value, :mimeType, nothing))
|
|
89
|
+
data = get(value, "data", get(value, :data, nothing))
|
|
90
|
+
if kind == "image" && mime_type isa AbstractString && data !== nothing
|
|
91
|
+
return string(mime_type), string(data), true
|
|
92
|
+
end
|
|
93
|
+
return "application/json", senpi_json(value), false
|
|
94
|
+
end
|
|
95
|
+
value isa AbstractVector && return "application/json", senpi_json(value), false
|
|
96
|
+
"text/plain", string(value), false
|
|
30
97
|
end
|
|
31
98
|
|
|
32
99
|
function display(value)
|
|
33
|
-
|
|
34
|
-
senpi_emit(Dict("type" => "display", "mimeType" =>
|
|
35
|
-
|
|
100
|
+
mime_type, payload, encoded = senpi_display_payload(value)
|
|
101
|
+
senpi_emit(Dict("type" => "display", "mimeType" => mime_type, "dataBase64" => encoded ? payload : senpi_base64(payload)))
|
|
102
|
+
nothing
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
function display_image(base64_value::AbstractString, mime_type::AbstractString="image/png")
|
|
106
|
+
senpi_emit(Dict("type" => "display", "mimeType" => string(mime_type), "dataBase64" => string(base64_value)))
|
|
107
|
+
nothing
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
function text(value)
|
|
111
|
+
senpi_emit(Dict("type" => "text", "stream" => "stdout", "data" => string(value)))
|
|
112
|
+
nothing
|
|
36
113
|
end
|
|
37
114
|
|
|
38
115
|
function print(values...)
|
|
39
|
-
|
|
40
|
-
return nothing
|
|
116
|
+
text(join(string.(values), ""))
|
|
41
117
|
end
|
|
42
118
|
|
|
43
|
-
function read(path::AbstractString)
|
|
44
|
-
|
|
119
|
+
function read(path::AbstractString, offset::Integer=1, limit::Union{Integer, Nothing}=nothing)
|
|
120
|
+
resolved = senpi_resolve_path(path)
|
|
121
|
+
content = Base.read(resolved, String)
|
|
122
|
+
if offset > 1 || limit !== nothing
|
|
123
|
+
lines = split(content, '\n'; keepempty=true)
|
|
124
|
+
start = max(1, Int(offset))
|
|
125
|
+
finish = limit === nothing ? length(lines) : min(length(lines), start + Int(limit) - 1)
|
|
126
|
+
content = start <= length(lines) ? join(lines[start:finish], '\n') : ""
|
|
127
|
+
end
|
|
128
|
+
senpi_emit_status("read", Dict("path" => resolved, "chars" => length(content), "preview" => first(content, min(length(content), 500))))
|
|
129
|
+
content
|
|
45
130
|
end
|
|
46
131
|
|
|
47
132
|
function write(path::AbstractString, content)
|
|
48
|
-
|
|
49
|
-
|
|
133
|
+
resolved = senpi_resolve_path(path)
|
|
134
|
+
mkpath(dirname(resolved))
|
|
135
|
+
data = string(content)
|
|
136
|
+
open(resolved, "w") do io
|
|
137
|
+
Base.write(io, data)
|
|
138
|
+
end
|
|
139
|
+
senpi_emit_status("write", Dict("path" => resolved, "chars" => length(data)))
|
|
140
|
+
resolved
|
|
50
141
|
end
|
|
51
142
|
|
|
52
143
|
function env(key=nothing, value=nothing)
|
|
53
144
|
if key === nothing
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
return
|
|
57
|
-
else
|
|
58
|
-
ENV[string(key)] = string(value)
|
|
59
|
-
return value
|
|
145
|
+
values = Dict{String, String}(string(name) => string(item) for (name, item) in ENV)
|
|
146
|
+
senpi_emit_status("env", Dict("count" => length(values), "keys" => sort(collect(keys(values)))[1:min(20, length(values))]))
|
|
147
|
+
return values
|
|
60
148
|
end
|
|
149
|
+
name = string(key)
|
|
150
|
+
if value === nothing
|
|
151
|
+
resolved = get(ENV, name, nothing)
|
|
152
|
+
senpi_emit_status("env", Dict("key" => name, "value" => resolved, "action" => "get"))
|
|
153
|
+
return resolved
|
|
154
|
+
end
|
|
155
|
+
resolved = string(value)
|
|
156
|
+
ENV[name] = resolved
|
|
157
|
+
senpi_emit_status("env", Dict("key" => name, "value" => resolved, "action" => "set"))
|
|
158
|
+
resolved
|
|
61
159
|
end
|
|
62
160
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
161
|
+
struct SenpiToolProxy end
|
|
162
|
+
|
|
163
|
+
struct SenpiToolCallable
|
|
164
|
+
name::String
|
|
66
165
|
end
|
|
67
166
|
|
|
68
|
-
function
|
|
69
|
-
|
|
70
|
-
|
|
167
|
+
function (callable::SenpiToolCallable)(args=nothing; kwargs...)
|
|
168
|
+
values = Dict{String, Any}()
|
|
169
|
+
if args !== nothing
|
|
170
|
+
args isa AbstractDict || error("tool.$(callable.name)(...) expects a dictionary of arguments")
|
|
171
|
+
for (key, value) in args
|
|
172
|
+
values[string(key)] = value
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
for (key, value) in kwargs
|
|
176
|
+
values[string(key)] = value
|
|
177
|
+
end
|
|
178
|
+
senpi_with_bridge_timeout_pause(() -> senpi_call_tool(callable.name, values))
|
|
71
179
|
end
|
|
72
180
|
|
|
73
|
-
|
|
181
|
+
Base.getproperty(::SenpiToolProxy, name::Symbol) = SenpiToolCallable(string(name))
|
|
182
|
+
const tool = SenpiToolProxy()
|
|
74
183
|
|
|
75
|
-
function
|
|
76
|
-
|
|
184
|
+
function completion(prompt::AbstractString; model="default", system=nothing, schema=nothing, kwargs...)
|
|
185
|
+
options = Dict{String, Any}("model" => model)
|
|
186
|
+
system !== nothing && (options["system"] = system)
|
|
187
|
+
schema !== nothing && (options["schema"] = schema)
|
|
188
|
+
for (key, value) in kwargs
|
|
189
|
+
options[string(key)] = value
|
|
190
|
+
end
|
|
191
|
+
response = senpi_with_bridge_timeout_pause(() -> senpi_completion(string(prompt), options))
|
|
192
|
+
response isa AbstractDict || return response
|
|
193
|
+
haskey(response, "value") && return response["value"]
|
|
194
|
+
get(response, "text", response)
|
|
77
195
|
end
|
|
78
196
|
|
|
79
|
-
|
|
197
|
+
function output(ids...; format="raw", offset=nothing, limit=nothing)
|
|
198
|
+
isempty(ids) && error("At least one output ID is required")
|
|
199
|
+
format in ("raw", "tail") || error("output() format must be 'raw' or 'tail'")
|
|
200
|
+
arguments = Dict{String, Any}("ids" => string.(ids), "format" => format)
|
|
201
|
+
offset !== nothing && (arguments["offset"] = offset)
|
|
202
|
+
limit !== nothing && (arguments["limit"] = limit)
|
|
203
|
+
senpi_with_bridge_timeout_pause(() -> senpi_call_tool("__output__", arguments))
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
function agent(prompt::AbstractString; agent="task", model=nothing, label=nothing, schema=nothing, isolated=nothing, apply=nothing, merge=nothing, handle=false, kwargs...)
|
|
207
|
+
arguments = Dict{String, Any}("prompt" => string(prompt), "agent" => agent)
|
|
208
|
+
for (key, value) in (("model", model), ("label", label), ("schema", schema), ("isolated", isolated), ("apply", apply), ("merge", merge))
|
|
209
|
+
value !== nothing && (arguments[key] = value)
|
|
210
|
+
end
|
|
211
|
+
for (key, value) in kwargs
|
|
212
|
+
arguments[string(key)] = value
|
|
213
|
+
end
|
|
214
|
+
handle && (arguments["handle"] = true)
|
|
215
|
+
response = senpi_with_bridge_timeout_pause(() -> senpi_call_tool("__agent__", arguments))
|
|
216
|
+
record = response isa AbstractDict ? response : Dict{String, Any}()
|
|
217
|
+
text_value = get(record, "text", response)
|
|
218
|
+
parsed = schema === nothing ? text_value : haskey(record, "data") ? record["data"] : senpi_json_parse(string(text_value))
|
|
219
|
+
handle || return parsed
|
|
220
|
+
result = Dict{String, Any}("text" => text_value, "output" => text_value, "id" => get(record, "id", nothing), "agent" => get(record, "agent", agent))
|
|
221
|
+
result["handle"] = get(record, "handle", result["id"] === nothing ? nothing : "agent://" * string(result["id"]))
|
|
222
|
+
schema !== nothing && (result["data"] = parsed)
|
|
223
|
+
result
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
function senpi_pool_map(items, callback)
|
|
227
|
+
values = collect(items)
|
|
228
|
+
isempty(values) && return Any[]
|
|
229
|
+
configured_width = get(senpi_connection, "parallelPoolWidth", 4)
|
|
230
|
+
width = configured_width isa Real && isfinite(configured_width) ? Int(floor(configured_width)) : 4
|
|
231
|
+
workers = min(max(width, 1), length(values))
|
|
232
|
+
tokens = Channel{Nothing}(workers)
|
|
233
|
+
for _ in 1:workers
|
|
234
|
+
put!(tokens, nothing)
|
|
235
|
+
end
|
|
236
|
+
results = Vector{Any}(undef, length(values))
|
|
237
|
+
errors = Dict{Int, Any}()
|
|
238
|
+
lock = ReentrantLock()
|
|
239
|
+
@sync for index in eachindex(values)
|
|
240
|
+
@async begin
|
|
241
|
+
take!(tokens)
|
|
242
|
+
try
|
|
243
|
+
results[index] = callback(values[index])
|
|
244
|
+
catch error
|
|
245
|
+
Base.lock(lock) do
|
|
246
|
+
errors[index] = error
|
|
247
|
+
end
|
|
248
|
+
finally
|
|
249
|
+
put!(tokens, nothing)
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
isempty(errors) || throw(errors[minimum(keys(errors))])
|
|
254
|
+
results
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
function parallel(thunks)
|
|
258
|
+
values = collect(thunks)
|
|
259
|
+
for thunk in values
|
|
260
|
+
applicable(thunk) || error("parallel() expects zero-argument callables")
|
|
261
|
+
end
|
|
262
|
+
senpi_pool_map(values, thunk -> thunk())
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
function pipeline(items, stages...)
|
|
266
|
+
values = collect(items)
|
|
267
|
+
for stage in stages
|
|
268
|
+
isempty(values) && return values
|
|
269
|
+
applicable(stage, first(values)) || error("pipeline() stages must be callables")
|
|
270
|
+
values = senpi_pool_map(values, stage)
|
|
271
|
+
end
|
|
272
|
+
values
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
function log(message)
|
|
276
|
+
senpi_emit(Dict("type" => "log", "message" => string(message)))
|
|
277
|
+
nothing
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
function phase(title)
|
|
281
|
+
senpi_emit(Dict("type" => "phase", "title" => string(title)))
|
|
282
|
+
nothing
|
|
283
|
+
end
|