@oh-my-pi/pi-coding-agent 16.1.12 → 16.1.14
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 +27 -0
- package/dist/cli.js +5650 -2860
- package/dist/types/config/settings-schema.d.ts +44 -14
- package/dist/types/cursor.d.ts +9 -9
- package/dist/types/eval/__tests__/julia-prelude.test.d.ts +1 -0
- package/dist/types/eval/backend-helpers.d.ts +23 -0
- package/dist/types/eval/executor-base.d.ts +118 -0
- package/dist/types/eval/index.d.ts +2 -0
- package/dist/types/eval/jl/executor.d.ts +44 -0
- package/dist/types/eval/jl/index.d.ts +11 -0
- package/dist/types/eval/jl/kernel.d.ts +28 -0
- package/dist/types/eval/jl/prelude.d.ts +1 -0
- package/dist/types/eval/jl/runtime.d.ts +22 -0
- package/dist/types/eval/kernel-base.d.ts +105 -0
- package/dist/types/eval/py/kernel.d.ts +3 -61
- package/dist/types/eval/rb/executor.d.ts +77 -0
- package/dist/types/eval/rb/index.d.ts +11 -0
- package/dist/types/eval/rb/kernel.d.ts +31 -0
- package/dist/types/eval/rb/prelude.d.ts +1 -0
- package/dist/types/eval/rb/runtime.d.ts +23 -0
- package/dist/types/eval/runtime-env.d.ts +24 -0
- package/dist/types/eval/types.d.ts +3 -3
- package/dist/types/extensibility/extensions/runner.d.ts +2 -15
- package/dist/types/extensibility/hooks/loader.d.ts +1 -25
- package/dist/types/extensibility/session-handler-types.d.ts +23 -0
- package/dist/types/jsonrpc/message-framing.d.ts +35 -0
- package/dist/types/mnemopi/embed-client.d.ts +7 -24
- package/dist/types/modes/components/chat-transcript-builder.d.ts +1 -1
- package/dist/types/modes/components/custom-editor.d.ts +11 -0
- package/dist/types/modes/components/selector-helpers.d.ts +53 -0
- package/dist/types/modes/interactive-mode.d.ts +0 -2
- package/dist/types/modes/theme/theme.d.ts +8 -1
- package/dist/types/modes/types.d.ts +0 -2
- package/dist/types/modes/utils/copy-targets.d.ts +1 -1
- package/dist/types/modes/utils/interactive-context-helpers.d.ts +14 -0
- package/dist/types/modes/utils/transcript-render-helpers.d.ts +54 -0
- package/dist/types/sdk.d.ts +1 -1
- package/dist/types/session/agent-session.d.ts +2 -2
- package/dist/types/stt/asr-client.d.ts +3 -29
- package/dist/types/subprocess/worker-client.d.ts +149 -0
- package/dist/types/subprocess/worker-runtime.d.ts +107 -0
- package/dist/types/tiny/title-client.d.ts +14 -34
- package/dist/types/tools/eval-backends.d.ts +6 -3
- package/dist/types/tools/eval-render.d.ts +6 -5
- package/dist/types/tools/eval.d.ts +13 -15
- package/dist/types/tools/index.d.ts +3 -3
- package/dist/types/tts/tts-client.d.ts +3 -28
- package/dist/types/tui/code-cell.d.ts +7 -0
- package/dist/types/utils/file-display-mode.d.ts +1 -1
- package/dist/types/web/parallel.d.ts +6 -0
- package/package.json +12 -12
- package/src/config/settings-schema.ts +50 -18
- package/src/config/settings.ts +5 -0
- package/src/dap/client.ts +13 -107
- package/src/eval/__tests__/julia-prelude.test.ts +77 -0
- package/src/eval/backend-helpers.ts +48 -0
- package/src/eval/executor-base.ts +425 -0
- package/src/eval/index.ts +2 -0
- package/src/eval/jl/executor.ts +540 -0
- package/src/eval/jl/index.ts +54 -0
- package/src/eval/jl/kernel.ts +235 -0
- package/src/eval/jl/prelude.jl +930 -0
- package/src/eval/jl/prelude.ts +3 -0
- package/src/eval/jl/runner.jl +634 -0
- package/src/eval/jl/runtime.ts +118 -0
- package/src/eval/js/index.ts +3 -14
- package/src/eval/kernel-base.ts +569 -0
- package/src/eval/py/executor.ts +43 -252
- package/src/eval/py/index.ts +9 -20
- package/src/eval/py/kernel.ts +29 -544
- package/src/eval/rb/executor.ts +504 -0
- package/src/eval/rb/index.ts +54 -0
- package/src/eval/rb/kernel.ts +230 -0
- package/src/eval/rb/prelude.rb +721 -0
- package/src/eval/rb/prelude.ts +3 -0
- package/src/eval/rb/runner.rb +474 -0
- package/src/eval/rb/runtime.ts +132 -0
- package/src/eval/runtime-env.ts +104 -0
- package/src/eval/types.ts +3 -3
- package/src/extensibility/extensions/runner.ts +4 -11
- package/src/extensibility/hooks/loader.ts +3 -21
- package/src/extensibility/session-handler-types.ts +21 -0
- package/src/internal-urls/docs-index.generated.txt +1 -1
- package/src/jsonrpc/message-framing.ts +142 -0
- package/src/lsp/client.ts +13 -109
- package/src/mnemopi/embed-client.ts +43 -198
- package/src/modes/components/agent-dashboard.ts +17 -40
- package/src/modes/components/chat-transcript-builder.ts +18 -102
- package/src/modes/components/custom-editor.ts +19 -0
- package/src/modes/components/extensions/extension-dashboard.ts +4 -13
- package/src/modes/components/extensions/extension-list.ts +16 -44
- package/src/modes/components/history-search.ts +4 -16
- package/src/modes/components/selector-helpers.ts +129 -0
- package/src/modes/components/settings-selector.ts +7 -5
- package/src/modes/components/tree-selector.ts +13 -18
- package/src/modes/controllers/event-controller.ts +3 -9
- package/src/modes/controllers/input-controller.ts +32 -54
- package/src/modes/interactive-mode.ts +5 -7
- package/src/modes/theme/theme.ts +35 -0
- package/src/modes/types.ts +0 -2
- package/src/modes/utils/copy-targets.ts +3 -2
- package/src/modes/utils/interactive-context-helpers.ts +27 -0
- package/src/modes/utils/transcript-render-helpers.ts +157 -0
- package/src/modes/utils/ui-helpers.ts +21 -126
- package/src/prompts/system/system-prompt.md +10 -10
- package/src/prompts/tools/bash.md +0 -1
- package/src/prompts/tools/eval.md +6 -4
- package/src/prompts/tools/find.md +0 -4
- package/src/prompts/tools/read.md +1 -2
- package/src/prompts/tools/replace.md +1 -1
- package/src/prompts/tools/search.md +0 -1
- package/src/sdk.ts +13 -7
- package/src/session/agent-session.ts +9 -7
- package/src/stt/asr-client.ts +35 -215
- package/src/stt/asr-worker.ts +29 -181
- package/src/subprocess/worker-client.ts +297 -0
- package/src/subprocess/worker-runtime.ts +277 -0
- package/src/task/executor.ts +4 -4
- package/src/tiny/title-client.ts +53 -219
- package/src/tiny/worker.ts +29 -180
- package/src/tools/eval-backends.ts +10 -3
- package/src/tools/eval-render.ts +17 -8
- package/src/tools/eval.ts +187 -22
- package/src/tools/index.ts +51 -28
- package/src/tts/tts-client.ts +38 -206
- package/src/tts/tts-worker.ts +23 -97
- package/src/tui/code-cell.ts +12 -1
- package/src/utils/file-display-mode.ts +2 -3
- package/src/web/parallel.ts +43 -42
- package/src/web/search/providers/parallel.ts +10 -99
|
@@ -39,16 +39,20 @@ import type { CompactionQueuedMessage, InteractiveModeContext } from "../../mode
|
|
|
39
39
|
import {
|
|
40
40
|
BACKGROUND_TAN_DISPATCH_MESSAGE_TYPE,
|
|
41
41
|
type CustomMessage,
|
|
42
|
-
isSilentAbort,
|
|
43
42
|
LSP_LATE_DIAGNOSTIC_MESSAGE_TYPE,
|
|
44
|
-
resolveAbortLabel,
|
|
45
43
|
SKILL_PROMPT_MESSAGE_TYPE,
|
|
46
44
|
type SkillPromptDetails,
|
|
47
45
|
} from "../../session/messages";
|
|
48
46
|
import type { SessionContext } from "../../session/session-context";
|
|
49
|
-
import {
|
|
50
|
-
import {
|
|
51
|
-
|
|
47
|
+
import { createAssistantMessageComponent } from "./interactive-context-helpers";
|
|
48
|
+
import {
|
|
49
|
+
assistantHasVisibleContent,
|
|
50
|
+
buildAsyncResultBlock,
|
|
51
|
+
buildFileMentionBlock,
|
|
52
|
+
buildIrcMessageCard,
|
|
53
|
+
normalizeToolArgs,
|
|
54
|
+
resolveAssistantErrorMessage,
|
|
55
|
+
} from "./transcript-render-helpers";
|
|
52
56
|
|
|
53
57
|
type TextBlock = { type: "text"; text: string };
|
|
54
58
|
interface RenderInitialMessagesOptions {
|
|
@@ -143,47 +147,7 @@ export class UiHelpers {
|
|
|
143
147
|
case "custom": {
|
|
144
148
|
if (message.display) {
|
|
145
149
|
if (message.customType === "async-result") {
|
|
146
|
-
|
|
147
|
-
message as CustomMessage<{
|
|
148
|
-
jobId?: string;
|
|
149
|
-
type?: "bash" | "task";
|
|
150
|
-
label?: string;
|
|
151
|
-
durationMs?: number;
|
|
152
|
-
jobs?: Array<{
|
|
153
|
-
jobId?: string;
|
|
154
|
-
type?: "bash" | "task";
|
|
155
|
-
label?: string;
|
|
156
|
-
durationMs?: number;
|
|
157
|
-
}>;
|
|
158
|
-
}>
|
|
159
|
-
).details;
|
|
160
|
-
const jobs =
|
|
161
|
-
details?.jobs && details.jobs.length > 0
|
|
162
|
-
? details.jobs
|
|
163
|
-
: [
|
|
164
|
-
{
|
|
165
|
-
jobId: details?.jobId,
|
|
166
|
-
type: details?.type,
|
|
167
|
-
label: details?.label,
|
|
168
|
-
durationMs: details?.durationMs,
|
|
169
|
-
},
|
|
170
|
-
];
|
|
171
|
-
const block = new TranscriptBlock();
|
|
172
|
-
for (const job of jobs) {
|
|
173
|
-
const jobId = job.jobId ?? "unknown";
|
|
174
|
-
const typeLabel = job.type ? `[${job.type}]` : "[job]";
|
|
175
|
-
const duration = typeof job.durationMs === "number" ? formatDuration(job.durationMs) : undefined;
|
|
176
|
-
const line = [
|
|
177
|
-
theme.fg("success", `${theme.status.done} Background job completed`),
|
|
178
|
-
theme.fg("dim", typeLabel),
|
|
179
|
-
theme.fg("accent", jobId),
|
|
180
|
-
duration ? theme.fg("dim", `(${duration})`) : undefined,
|
|
181
|
-
]
|
|
182
|
-
.filter(Boolean)
|
|
183
|
-
.join(" ");
|
|
184
|
-
block.addChild(new Text(line, 1, 0));
|
|
185
|
-
}
|
|
186
|
-
this.ctx.chatContainer.addChild(block);
|
|
150
|
+
this.ctx.chatContainer.addChild(buildAsyncResultBlock(message));
|
|
187
151
|
break;
|
|
188
152
|
}
|
|
189
153
|
if (message.customType === LSP_LATE_DIAGNOSTIC_MESSAGE_TYPE) {
|
|
@@ -213,33 +177,7 @@ export class UiHelpers {
|
|
|
213
177
|
message.customType === "irc:autoreply" ||
|
|
214
178
|
message.customType === "irc:relay"
|
|
215
179
|
) {
|
|
216
|
-
const
|
|
217
|
-
message as CustomMessage<{
|
|
218
|
-
from?: string;
|
|
219
|
-
to?: string;
|
|
220
|
-
message?: string;
|
|
221
|
-
body?: string;
|
|
222
|
-
replyTo?: string;
|
|
223
|
-
}>
|
|
224
|
-
).details;
|
|
225
|
-
const kind =
|
|
226
|
-
message.customType === "irc:incoming"
|
|
227
|
-
? ("incoming" as const)
|
|
228
|
-
: message.customType === "irc:autoreply"
|
|
229
|
-
? ("autoreply" as const)
|
|
230
|
-
: ("relay" as const);
|
|
231
|
-
const card = createIrcMessageCard(
|
|
232
|
-
{
|
|
233
|
-
kind,
|
|
234
|
-
from: details?.from,
|
|
235
|
-
to: details?.to,
|
|
236
|
-
body: kind === "incoming" ? details?.message : details?.body,
|
|
237
|
-
replyTo: details?.replyTo,
|
|
238
|
-
timestamp: message.timestamp,
|
|
239
|
-
},
|
|
240
|
-
() => this.ctx.toolOutputExpanded,
|
|
241
|
-
theme,
|
|
242
|
-
);
|
|
180
|
+
const card = buildIrcMessageCard(message, () => this.ctx.toolOutputExpanded);
|
|
243
181
|
this.ctx.chatContainer.addChild(card);
|
|
244
182
|
return [card];
|
|
245
183
|
}
|
|
@@ -284,25 +222,7 @@ export class UiHelpers {
|
|
|
284
222
|
}
|
|
285
223
|
case "fileMention": {
|
|
286
224
|
// Render compact file mention display
|
|
287
|
-
const block =
|
|
288
|
-
for (const file of message.files) {
|
|
289
|
-
let suffix: string;
|
|
290
|
-
if (file.skippedReason === "tooLarge") {
|
|
291
|
-
const size = typeof file.byteSize === "number" ? formatBytes(file.byteSize) : "unknown size";
|
|
292
|
-
suffix = `(skipped: ${size})`;
|
|
293
|
-
} else {
|
|
294
|
-
suffix = file.image
|
|
295
|
-
? "(image)"
|
|
296
|
-
: file.lineCount === undefined
|
|
297
|
-
? "(unknown lines)"
|
|
298
|
-
: `(${file.lineCount} lines)`;
|
|
299
|
-
}
|
|
300
|
-
const text = `${theme.fg("dim", `${theme.tree.last} `)}${theme.fg("muted", "Read")} ${theme.fg(
|
|
301
|
-
"accent",
|
|
302
|
-
file.path,
|
|
303
|
-
)} ${theme.fg("dim", suffix)}`;
|
|
304
|
-
block.addChild(new Text(text, 0, 0));
|
|
305
|
-
}
|
|
225
|
+
const block = buildFileMentionBlock(message.files, 0);
|
|
306
226
|
if (block.children.length > 0) this.ctx.chatContainer.addChild(block);
|
|
307
227
|
break;
|
|
308
228
|
}
|
|
@@ -326,14 +246,7 @@ export class UiHelpers {
|
|
|
326
246
|
break;
|
|
327
247
|
}
|
|
328
248
|
case "assistant": {
|
|
329
|
-
const assistantComponent =
|
|
330
|
-
message,
|
|
331
|
-
this.ctx.hideThinkingBlock,
|
|
332
|
-
() => this.ctx.ui.requestRender(),
|
|
333
|
-
this.ctx.viewSession.extensionRunner?.getAssistantThinkingRenderers(),
|
|
334
|
-
this.ctx.ui.imageBudget,
|
|
335
|
-
this.ctx.proseOnlyThinking,
|
|
336
|
-
);
|
|
249
|
+
const assistantComponent = createAssistantMessageComponent(this.ctx, message);
|
|
337
250
|
this.ctx.chatContainer.addChild(assistantComponent);
|
|
338
251
|
break;
|
|
339
252
|
}
|
|
@@ -425,11 +338,7 @@ export class UiHelpers {
|
|
|
425
338
|
this.ctx.lastAssistantUsage = usage;
|
|
426
339
|
}
|
|
427
340
|
}
|
|
428
|
-
const hasVisibleAssistantContent = message
|
|
429
|
-
content =>
|
|
430
|
-
(content.type === "text" && canonicalizeMessage(content.text)) ||
|
|
431
|
-
(content.type === "thinking" && canonicalizeMessage(content.thinking)),
|
|
432
|
-
);
|
|
341
|
+
const hasVisibleAssistantContent = assistantHasVisibleContent(message);
|
|
433
342
|
if (hasVisibleAssistantContent) {
|
|
434
343
|
// Rebuild reconstructs immutable history; seal (not finalize) so the
|
|
435
344
|
// group freezes even if a read's result was never persisted —
|
|
@@ -438,14 +347,10 @@ export class UiHelpers {
|
|
|
438
347
|
readGroup?.seal();
|
|
439
348
|
readGroup = null;
|
|
440
349
|
}
|
|
441
|
-
const
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
? message.stopReason === "aborted"
|
|
446
|
-
? resolveAbortLabel(message.errorMessage, this.ctx.viewSession.retryAttempt)
|
|
447
|
-
: message.errorMessage || "Error"
|
|
448
|
-
: null;
|
|
350
|
+
const { hasErrorStop, errorMessage } = resolveAssistantErrorMessage(
|
|
351
|
+
message,
|
|
352
|
+
this.ctx.viewSession.retryAttempt,
|
|
353
|
+
);
|
|
449
354
|
|
|
450
355
|
// Render tool call components
|
|
451
356
|
for (const content of message.content) {
|
|
@@ -474,10 +379,7 @@ export class UiHelpers {
|
|
|
474
379
|
content.id,
|
|
475
380
|
);
|
|
476
381
|
} else {
|
|
477
|
-
const normalizedArgs =
|
|
478
|
-
content.arguments && typeof content.arguments === "object" && !Array.isArray(content.arguments)
|
|
479
|
-
? (content.arguments as Record<string, unknown>)
|
|
480
|
-
: {};
|
|
382
|
+
const normalizedArgs = normalizeToolArgs(content.arguments);
|
|
481
383
|
readToolCallArgs.set(content.id, normalizedArgs);
|
|
482
384
|
if (assistantComponent) {
|
|
483
385
|
readToolCallAssistantComponents.set(content.id, assistantComponent);
|
|
@@ -647,10 +549,7 @@ export class UiHelpers {
|
|
|
647
549
|
}
|
|
648
550
|
|
|
649
551
|
clearEditor(): void {
|
|
650
|
-
this.ctx.editor.
|
|
651
|
-
this.ctx.pendingImages = [];
|
|
652
|
-
this.ctx.pendingImageLinks = [];
|
|
653
|
-
this.ctx.editor.imageLinks = undefined;
|
|
552
|
+
this.ctx.editor.clearDraft();
|
|
654
553
|
this.ctx.ui.requestRender();
|
|
655
554
|
}
|
|
656
555
|
|
|
@@ -719,11 +618,7 @@ export class UiHelpers {
|
|
|
719
618
|
queueCompactionMessage(text: string, mode: "steer" | "followUp", images?: ImageContent[]): void {
|
|
720
619
|
const queuedImages = images && images.length > 0 ? images : undefined;
|
|
721
620
|
this.ctx.compactionQueuedMessages.push({ text, mode, images: queuedImages } as CompactionQueuedMessage);
|
|
722
|
-
this.ctx.editor.
|
|
723
|
-
this.ctx.editor.setText("");
|
|
724
|
-
this.ctx.editor.imageLinks = undefined;
|
|
725
|
-
this.ctx.pendingImages = [];
|
|
726
|
-
this.ctx.pendingImageLinks = [];
|
|
621
|
+
this.ctx.editor.clearDraft(text);
|
|
727
622
|
this.ctx.updatePendingMessagesDisplay();
|
|
728
623
|
this.ctx.showStatus(
|
|
729
624
|
queuedImages ? "Queued message with image for after compaction" : "Queued message for after compaction",
|
|
@@ -101,17 +101,17 @@ Use tools whenever they improve correctness, completeness, or grounding.
|
|
|
101
101
|
{{#if secretsEnabled}}- Redacted `#XXXX#` tokens in output are opaque strings.{{/if}}
|
|
102
102
|
{{#has tools "inspect_image"}}- Image tasks: prefer `{{toolRefs.inspect_image}}` over `{{toolRefs.read}}` to spare session context.{{/has}}
|
|
103
103
|
|
|
104
|
-
# Specialized
|
|
105
|
-
|
|
106
|
-
{{#has tools "read"}}- File or directory reads → `{{toolRefs.read}}
|
|
107
|
-
{{#has tools "edit"}}- Surgical edits → `{{toolRefs.edit}}
|
|
108
|
-
{{#has tools "write"}}- Create or overwrite → `{{toolRefs.write}}
|
|
109
|
-
{{#has tools "lsp"}}- Code intelligence → `{{toolRefs.lsp}}
|
|
110
|
-
{{#has tools "search"}}- Regex search → `{{toolRefs.search}}
|
|
111
|
-
{{#has tools "find"}}- Globbing → `{{toolRefs.find}}
|
|
104
|
+
# Specialized Tools
|
|
105
|
+
Dedicated tools add gitignore semantics, structured output, and line anchors a raw shell command lacks — reach for them first when they fit:
|
|
106
|
+
{{#has tools "read"}}- File or directory reads → `{{toolRefs.read}}` (a directory path lists entries).{{/has}}
|
|
107
|
+
{{#has tools "edit"}}- Surgical edits → `{{toolRefs.edit}}`.{{/has}}
|
|
108
|
+
{{#has tools "write"}}- Create or overwrite → `{{toolRefs.write}}`.{{/has}}
|
|
109
|
+
{{#has tools "lsp"}}- Code intelligence → `{{toolRefs.lsp}}`.{{/has}}
|
|
110
|
+
{{#has tools "search"}}- Regex search → `{{toolRefs.search}}`.{{/has}}
|
|
111
|
+
{{#has tools "find"}}- Globbing → `{{toolRefs.find}}`.{{/has}}
|
|
112
112
|
{{#has tools "eval"}}- Quick compute → `{{toolRefs.eval}}`; you SHOULD go step by step.{{/has}}
|
|
113
|
-
{{#has tools "bash"}}- Use `{{toolRefs.bash}}` for terminal work—builds, tests, git, package managers—and pipelines that COMPUTE a fact: `wc -l`, `sort | uniq -c`, `comm`, `diff a b`, checksums.
|
|
114
|
-
- Litmus: produces a count, frequency, set difference, or checksum no tool returns → bash.
|
|
113
|
+
{{#has tools "bash"}}- Use `{{toolRefs.bash}}` for terminal work—builds, tests, git, package managers—and pipelines that COMPUTE a fact: `wc -l`, `sort | uniq -c`, `comm`, `diff a b`, checksums.
|
|
114
|
+
- Litmus: produces a count, frequency, set difference, or checksum no tool returns → bash. Otherwise a dedicated tool usually fits.{{/has}}
|
|
115
115
|
|
|
116
116
|
{{#has tools "report_tool_issue"}}
|
|
117
117
|
<critical>
|
|
@@ -14,7 +14,6 @@ Runs bash in a shell session — terminal ops: git, bun, cargo, python.
|
|
|
14
14
|
</instruction>
|
|
15
15
|
|
|
16
16
|
<critical>
|
|
17
|
-
- NEVER shell out to fetch, display, list, page, or search what a dedicated tool serves: `cat`/`head`/`tail`/`less`/`more`/`ls` → `read`; `grep`/`rg`/`ag`/`ack` → `search`; `find`/`fd` → `find`; `sed -i`/`perl -i`/`awk -i` → `edit`; `echo >`/heredoc → `write`. Tools keep gitignore semantics, line anchors, structured output shell loses.
|
|
18
17
|
- NEVER trim or silence output: no `| head -n N`, `| tail -n N`, `| less`, `2>&1`, `2>/dev/null`. stderr already merged; long output auto-truncated, FULL capture kept at `artifact://<id>`.
|
|
19
18
|
- Pipelines that COMPUTE a new fact are correct bash: `wc -l`, `sort | uniq -c`, `comm`, `cut`, `diff a b`, `shasum`. Litmus: produces a count, frequency table, set difference, or checksum no tool returns → bash. Merely moves or trims bytes a tool can fetch → use the tool.
|
|
20
19
|
</critical>
|
|
@@ -5,7 +5,7 @@ Cells run in array order. State persists per language across cells, tool calls,
|
|
|
5
5
|
|
|
6
6
|
Cell fields:
|
|
7
7
|
|
|
8
|
-
- `language` — {{#if py}}`"py"` IPython kernel{{/if}}{{#ifAll py js}}, {{/ifAll}}{{#if js}}`"js"` persistent JavaScript VM{{/if}}.
|
|
8
|
+
- `language` — {{#if py}}`"py"` IPython kernel{{/if}}{{#ifAll py js}}, {{/ifAll}}{{#if js}}`"js"` persistent JavaScript VM{{/if}}{{#if rb}}{{#ifAny py js}}, {{/ifAny}}`"rb"` persistent Ruby kernel{{/if}}{{#if jl}}{{#ifAny py js rb}}, {{/ifAny}}`"jl"` persistent Julia kernel{{/if}}.
|
|
9
9
|
- `code` — cell body, verbatim. Newlines/quotes JSON-encoded; no fences, no headers.
|
|
10
10
|
- `title` (optional) — short transcript label (e.g. `"imports"`).
|
|
11
11
|
- `timeout` (optional) — per-cell seconds. Raise only for heavy compute or long non-agent tool calls.
|
|
@@ -13,11 +13,13 @@ Cell fields:
|
|
|
13
13
|
|
|
14
14
|
Work incrementally — one logical step per cell (imports, define, test, use), many small cells per call; workflow notes in the assistant message or `title`, never in cell code.
|
|
15
15
|
{{#if py}}Live event loop: use top-level `await` directly; `asyncio.run(…)` raises "cannot be called from a running event loop".{{/if}}
|
|
16
|
+
{{#if rb}}Ruby: synchronous; helper options are keyword args (e.g. `tree(".", max_depth: 2)`); the last expression auto-displays unless it is `nil`, an assignment, or a definition (like IRB).{{/if}}
|
|
17
|
+
{{#if jl}}Julia: synchronous; helper options are standard keyword args (e.g. `tree(max_depth=2)`); the last expression auto-displays unless it is an assignment or a definition (like the Julia REPL).{{/if}}
|
|
16
18
|
Errors name the failing cell ("Cell 3 failed") — resubmit the fixed cell + any remaining.
|
|
17
19
|
</instruction>
|
|
18
20
|
|
|
19
21
|
<prelude>
|
|
20
|
-
{{#ifAll py js}}Same helpers + arg order, both runtimes. Python: sync, options = trailing kwargs. JS: async/`await`able, options = ONE trailing object literal, never positional (extras throw).{{else}}{{#if py}}Sync; options = trailing kwargs.{{/if}}{{#if js}}Async/`await`able; options = ONE trailing object literal, never positional (extras throw).{{/if}}{{/ifAll}}
|
|
22
|
+
{{#ifAll py js}}Same helpers + arg order, both runtimes. Python: sync, options = trailing kwargs. JS: async/`await`able, options = ONE trailing object literal, never positional (extras throw).{{else}}{{#if py}}Sync; options = trailing kwargs.{{/if}}{{#if js}}Async/`await`able; options = ONE trailing object literal, never positional (extras throw).{{/if}}{{/ifAll}}{{#if rb}} Ruby: sync, options = trailing keyword args.{{/if}}{{#if jl}} Julia: sync, options = trailing keyword args.{{/if}}
|
|
21
23
|
```
|
|
22
24
|
display(value) → None
|
|
23
25
|
Cell output; figures/images/dataframes shown natively.
|
|
@@ -55,13 +57,13 @@ log(message) → None
|
|
|
55
57
|
phase(title) → None
|
|
56
58
|
Phase grouping subsequent status lines.
|
|
57
59
|
budget → per-turn token budget
|
|
58
|
-
{{#if py}}`budget.total` (ceiling or None), `budget.spent()`, `budget.remaining()` (math.inf when no ceiling), `budget.hard`.{{/if}}{{#if js}}`await budget.total()` (ceiling or null), `await budget.spent()`, `await budget.remaining()` (Infinity when no ceiling), `await budget.hard()`.{{/if}} Ceiling: `+Nk` (advisory) or `+Nk!`/Goal Mode (hard — `agent()` won't spawn past it); spend still tracked.
|
|
60
|
+
{{#if py}}`budget.total` (ceiling or None), `budget.spent()`, `budget.remaining()` (math.inf when no ceiling), `budget.hard`.{{/if}}{{#if js}}`await budget.total()` (ceiling or null), `await budget.spent()`, `await budget.remaining()` (Infinity when no ceiling), `await budget.hard()`.{{/if}}{{#if rb}} Ruby: `budget.total` (ceiling or nil), `budget.spent`, `budget.remaining` (Float::INFINITY when no ceiling), `budget.hard`.{{/if}}{{#if jl}} Julia: `budget.total` (ceiling or nothing), `budget.spent()`, `budget.remaining()` (Inf when no ceiling), `budget.hard`.{{/if}} Ceiling: `+Nk` (advisory) or `+Nk!`/Goal Mode (hard — `agent()` won't spawn past it); spend still tracked.
|
|
59
61
|
```
|
|
60
62
|
</prelude>
|
|
61
63
|
{{#if spawns}}
|
|
62
64
|
<dag>
|
|
63
65
|
Pipe handles through stage helpers to build a dependency graph — acyclic waves:
|
|
64
|
-
- **Name nodes.** Capture each `agent(…, {{#if py}}return_handle=True{{/if}}{{#if js}}{ returnHandle: true }{{/if}})` result; carries `handle` (`agent://<id>`) + `output`.
|
|
66
|
+
- **Name nodes.** Capture each `agent(…, {{#if py}}return_handle=True{{/if}}{{#if js}}{ returnHandle: true }{{/if}}{{#if jl}}return_handle=true{{/if}})` result; carries `handle` (`agent://<id>`) + `output`.
|
|
65
67
|
- **Wire edges by reference.** Put an upstream node's `handle`/`output` in the dependent stage's prompt — large transcript never re-inlined. Bulk: `write("local://<name>.md", …)`, pass the URI.
|
|
66
68
|
- **`pipeline(items, *stages)` = staged waves**, barrier between stages (every item clears stage N before any enters N+1). **`parallel(thunks)` = one wave** of independent nodes.
|
|
67
69
|
- **Isolate failure.** A raising node re-raises the lowest-index error, aborts its wave; wrap risky nodes in try/except so a failure degrades only its dependent subtree, independent branches finish.
|
|
@@ -13,7 +13,3 @@ Matching paths sorted by mtime (newest first), grouped under `# <dir>/` headers
|
|
|
13
13
|
<avoid>
|
|
14
14
|
Open-ended searches needing multiple rounds of globbing/searching: you MUST use the Task tool instead.
|
|
15
15
|
</avoid>
|
|
16
|
-
|
|
17
|
-
<critical>
|
|
18
|
-
- You MUST use the built-in Find tool for every file-name lookup. NEVER shell out to `find`, `fd`, `locate`, `ls`, or `git ls-files` via Bash — they ignore `.gitignore`, blow past result limits, and waste tokens.
|
|
19
|
-
</critical>
|
|
@@ -70,7 +70,6 @@ For `.sqlite`, `.sqlite3`, `.db`, `.db3`:
|
|
|
70
70
|
All URI schemes take the same line selectors. `artifact://<id>` recovers full output a bash/eval/tool result spilled or truncated. `history://<agentId>` = agent transcript; bare `history://` lists agents.
|
|
71
71
|
|
|
72
72
|
<critical>
|
|
73
|
-
-
|
|
74
|
-
- Line ranges go in the selector (`path="src/foo.ts:50-200"`) — NEVER `sed -n`, `awk NR`, or `head`/`tail` pipelines.
|
|
73
|
+
- Line ranges go in the selector: `path="src/foo.ts:50-200"`.
|
|
75
74
|
- Summary footer names elided ranges? Re-issue ONLY those ranges. NEVER guess `..`/`…` content.
|
|
76
75
|
</critical>
|
|
@@ -25,5 +25,5 @@ For pattern-addressed bulk changes, bash is more efficient:
|
|
|
25
25
|
|Bulk replace across files|`sd 'pattern' 'replacement' **/*.ts`|
|
|
26
26
|
|
|
27
27
|
Use Replace when _content itself_ identifies location; use `ast_edit` for structure-aware codemods.
|
|
28
|
-
|
|
28
|
+
For in-place edits prefer this tool or `write` — you get a diff preview and fuzzy matching.
|
|
29
29
|
</bash-alternatives>
|
|
@@ -17,6 +17,5 @@ Searches files using regex.
|
|
|
17
17
|
</output>
|
|
18
18
|
|
|
19
19
|
<critical>
|
|
20
|
-
- MUST use built-in `search` for any content search. NEVER shell out to `grep`, `rg`, `ripgrep`, `ag`, `ack`, `git grep`, `awk`, `sed`-for-search, or any CLI search via Bash — not even for one match or a quick check.
|
|
21
20
|
- Open-ended search needing multiple rounds? MUST use the Task tool with the explore subagent, NOT chained `search` calls.
|
|
22
21
|
</critical>
|
package/src/sdk.ts
CHANGED
|
@@ -46,7 +46,9 @@ import { Settings, type SkillsSettings } from "./config/settings";
|
|
|
46
46
|
import { CursorExecHandlers } from "./cursor";
|
|
47
47
|
import "./discovery";
|
|
48
48
|
import { initializeWithSettings } from "./discovery";
|
|
49
|
+
import { disposeAllJuliaKernelSessions, disposeJuliaKernelSessionsByOwner } from "./eval/jl/executor";
|
|
49
50
|
import { disposeAllKernelSessions, disposeKernelSessionsByOwner } from "./eval/py/executor";
|
|
51
|
+
import { disposeAllRubyKernelSessions, disposeRubyKernelSessionsByOwner } from "./eval/rb/executor";
|
|
50
52
|
import { defaultEvalSessionId } from "./eval/session-id";
|
|
51
53
|
import {
|
|
52
54
|
type CustomCommandsLoadResult,
|
|
@@ -472,7 +474,7 @@ export interface CreateAgentSessionOptions {
|
|
|
472
474
|
|
|
473
475
|
/** Enable LSP integration (tool, formatting, diagnostics, warmup). Default: true */
|
|
474
476
|
enableLsp?: boolean;
|
|
475
|
-
/** Skip
|
|
477
|
+
/** Skip subprocess-kernel availability checks and prelude warmup */
|
|
476
478
|
skipPythonPreflight?: boolean;
|
|
477
479
|
/** Tool names explicitly requested (enables disabled-by-default tools) */
|
|
478
480
|
toolNames?: string[];
|
|
@@ -866,12 +868,14 @@ function registerSshCleanup(): void {
|
|
|
866
868
|
postmortem.register("ssh-cleanup", cleanupSshResources);
|
|
867
869
|
}
|
|
868
870
|
|
|
869
|
-
let
|
|
871
|
+
let evalCleanupRegistered = false;
|
|
870
872
|
|
|
871
|
-
function
|
|
872
|
-
if (
|
|
873
|
-
|
|
873
|
+
function registerEvalCleanup(): void {
|
|
874
|
+
if (evalCleanupRegistered) return;
|
|
875
|
+
evalCleanupRegistered = true;
|
|
874
876
|
postmortem.register("python-cleanup", disposeAllKernelSessions);
|
|
877
|
+
postmortem.register("ruby-cleanup", disposeAllRubyKernelSessions);
|
|
878
|
+
postmortem.register("julia-cleanup", disposeAllJuliaKernelSessions);
|
|
875
879
|
}
|
|
876
880
|
|
|
877
881
|
function customToolToDefinition(tool: CustomTool): ToolDefinition {
|
|
@@ -1080,7 +1084,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1080
1084
|
const eventBus = options.eventBus ?? new EventBus();
|
|
1081
1085
|
|
|
1082
1086
|
registerSshCleanup();
|
|
1083
|
-
|
|
1087
|
+
registerEvalCleanup();
|
|
1084
1088
|
|
|
1085
1089
|
// Pin authStorage to modelRegistry.authStorage: ModelRegistry.getApiKey() routes refresh
|
|
1086
1090
|
// failures through that instance, so any divergent storage handed to the bridge / mcpManager
|
|
@@ -2693,7 +2697,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2693
2697
|
const originalDispose = session.dispose.bind(session);
|
|
2694
2698
|
session.dispose = async () => {
|
|
2695
2699
|
try {
|
|
2696
|
-
// Reject new session work (
|
|
2700
|
+
// Reject new session work (eval starts) the moment disposal
|
|
2697
2701
|
// begins — the lifecycle await below opens an async gap before
|
|
2698
2702
|
// AgentSession.dispose() would otherwise set its guards.
|
|
2699
2703
|
session.beginDispose();
|
|
@@ -2913,6 +2917,8 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2913
2917
|
await asyncJobManager.dispose({ timeoutMs: 3_000 });
|
|
2914
2918
|
}
|
|
2915
2919
|
await disposeKernelSessionsByOwner(evalKernelOwnerId);
|
|
2920
|
+
await disposeRubyKernelSessionsByOwner(evalKernelOwnerId);
|
|
2921
|
+
await disposeJuliaKernelSessionsByOwner(evalKernelOwnerId);
|
|
2916
2922
|
if (ownsAuthStorage) authStorage.close();
|
|
2917
2923
|
}
|
|
2918
2924
|
} catch (cleanupError) {
|
|
@@ -164,12 +164,14 @@ import { RawSseDebugBuffer } from "../debug/raw-sse-buffer";
|
|
|
164
164
|
import { loadCapability } from "../discovery";
|
|
165
165
|
import { expandApplyPatchToEntries, normalizeDiff, normalizeToLF, ParseError, previewPatch, stripBom } from "../edit";
|
|
166
166
|
import { getFileSnapshotStore } from "../edit/file-snapshot-store";
|
|
167
|
+
import { disposeJuliaKernelSessionsByOwner } from "../eval/jl/executor";
|
|
167
168
|
import { namespaceSessionId as namespacePythonSessionId } from "../eval/py";
|
|
168
169
|
import {
|
|
169
170
|
disposeKernelSessionsByOwner,
|
|
170
171
|
executePython as executePythonCommand,
|
|
171
172
|
type PythonResult,
|
|
172
173
|
} from "../eval/py/executor";
|
|
174
|
+
import { disposeRubyKernelSessionsByOwner } from "../eval/rb/executor";
|
|
173
175
|
import { defaultEvalSessionId } from "../eval/session-id";
|
|
174
176
|
import { type BashResult, executeBash as executeBashCommand } from "../exec/bash-executor";
|
|
175
177
|
import type { TtsrManager, TtsrMatchContext } from "../export/ttsr";
|
|
@@ -520,7 +522,7 @@ export interface AgentSessionConfig {
|
|
|
520
522
|
obfuscator?: SecretObfuscator;
|
|
521
523
|
/** Inherited eval executor session id from a parent agent. */
|
|
522
524
|
parentEvalSessionId?: string;
|
|
523
|
-
/** Logical owner for retained
|
|
525
|
+
/** Logical owner for retained eval kernels created by this session. */
|
|
524
526
|
evalKernelOwnerId?: string;
|
|
525
527
|
/**
|
|
526
528
|
* AsyncJobManager that this session installed as the process-global instance.
|
|
@@ -4173,7 +4175,7 @@ export class AgentSession {
|
|
|
4173
4175
|
|
|
4174
4176
|
/**
|
|
4175
4177
|
* Synchronously mark the session as disposing so new work is rejected
|
|
4176
|
-
* immediately:
|
|
4178
|
+
* immediately: eval starts throw, queued asides are dropped, and the
|
|
4177
4179
|
* aside provider is detached. Idempotent; `dispose()` runs it first.
|
|
4178
4180
|
*
|
|
4179
4181
|
* Wrappers that await other teardown before delegating to `dispose()` MUST
|
|
@@ -4235,13 +4237,13 @@ export class AgentSession {
|
|
|
4235
4237
|
AsyncJobManager.setInstance(undefined);
|
|
4236
4238
|
}
|
|
4237
4239
|
}
|
|
4238
|
-
const
|
|
4239
|
-
if (!
|
|
4240
|
-
logger.warn(
|
|
4241
|
-
"Detaching retained Python kernel ownership during dispose while Python execution is still active",
|
|
4242
|
-
);
|
|
4240
|
+
const evalExecutionsSettled = await this.#prepareEvalExecutionsForDispose();
|
|
4241
|
+
if (!evalExecutionsSettled) {
|
|
4242
|
+
logger.warn("Detaching retained eval-kernel ownership during dispose while eval execution is still active");
|
|
4243
4243
|
}
|
|
4244
4244
|
await disposeKernelSessionsByOwner(this.#evalKernelOwnerId);
|
|
4245
|
+
await disposeRubyKernelSessionsByOwner(this.#evalKernelOwnerId);
|
|
4246
|
+
await disposeJuliaKernelSessionsByOwner(this.#evalKernelOwnerId);
|
|
4245
4247
|
await shutdownTinyTitleClient();
|
|
4246
4248
|
this.#releasePowerAssertion();
|
|
4247
4249
|
await this.sessionManager.close();
|