@skaile/workspaces 4.17.0 → 4.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/dist/{asset-feeds-MQKQDF3R.js → asset-feeds-VXK6SHWK.js} +4 -4
- package/dist/{asset-feeds-MQKQDF3R.js.map → asset-feeds-VXK6SHWK.js.map} +1 -1
- package/dist/asset-manager/index.js +1 -1
- package/dist/bridge/codex-app-server.js +2 -1
- package/dist/bridge/drivers/claude-sdk.js +21 -151
- package/dist/bridge/drivers/claude-sdk.js.map +1 -1
- package/dist/bridge/drivers/codex.js +4 -3
- package/dist/bridge/drivers/codex.js.map +1 -1
- package/dist/bridge/drivers/continue.js +4 -3
- package/dist/bridge/drivers/continue.js.map +1 -1
- package/dist/bridge/drivers/echo.js +1 -1
- package/dist/bridge/drivers/gemini.js +6 -5
- package/dist/bridge/drivers/goose.js +4 -3
- package/dist/bridge/drivers/goose.js.map +1 -1
- package/dist/bridge/drivers/omp.js +813 -40
- package/dist/bridge/drivers/omp.js.map +1 -1
- package/dist/bridge/drivers/opencode.js +4 -3
- package/dist/bridge/drivers/opencode.js.map +1 -1
- package/dist/bridge/drivers/qwen.js +6 -5
- package/dist/bridge/drivers/qwen.js.map +1 -1
- package/dist/bridge/index.js +5 -4
- package/dist/bridge/src/agent-exec.d.ts +6 -0
- package/dist/bridge/src/agent-exec.d.ts.map +1 -1
- package/dist/bridge/src/agent-transcript.d.ts +18 -0
- package/dist/bridge/src/agent-transcript.d.ts.map +1 -0
- package/dist/bridge/src/codex-app-server.d.ts.map +1 -1
- package/dist/bridge/src/drivers/_subprocess-cli.d.ts.map +1 -1
- package/dist/bridge/src/drivers/claude-sdk.d.ts +2 -0
- package/dist/bridge/src/drivers/claude-sdk.d.ts.map +1 -1
- package/dist/bridge/src/drivers/omp.d.ts +287 -7
- package/dist/bridge/src/drivers/omp.d.ts.map +1 -1
- package/dist/bridge/src/drivers/scrub-transcript.d.ts +29 -0
- package/dist/bridge/src/drivers/scrub-transcript.d.ts.map +1 -1
- package/dist/bridge/src/index.d.ts +2 -0
- package/dist/bridge/src/index.d.ts.map +1 -1
- package/dist/bridge/src/normalizer.d.ts +5 -0
- package/dist/bridge/src/normalizer.d.ts.map +1 -1
- package/dist/{chunk-C3YE4REG.js → chunk-25BOOOSM.js} +3 -3
- package/dist/{chunk-C3YE4REG.js.map → chunk-25BOOOSM.js.map} +1 -1
- package/dist/{chunk-XRTOSEF3.js → chunk-66MJRB6K.js} +2 -2
- package/dist/{chunk-XRTOSEF3.js.map → chunk-66MJRB6K.js.map} +1 -1
- package/dist/{chunk-NYDTZ2MK.js → chunk-66WUZ3XL.js} +5 -5
- package/dist/{chunk-NYDTZ2MK.js.map → chunk-66WUZ3XL.js.map} +1 -1
- package/dist/{chunk-3W7AOGPY.js → chunk-6S5KL76M.js} +225 -46
- package/dist/chunk-6S5KL76M.js.map +1 -0
- package/dist/{chunk-4RKCOURU.js → chunk-6V3DMJPL.js} +3 -3
- package/dist/{chunk-4RKCOURU.js.map → chunk-6V3DMJPL.js.map} +1 -1
- package/dist/{chunk-6F4TIY7X.js → chunk-EBYSCP6J.js} +4 -4
- package/dist/{chunk-6F4TIY7X.js.map → chunk-EBYSCP6J.js.map} +1 -1
- package/dist/{chunk-D5CRFGDL.js → chunk-EEODEEKX.js} +16 -3
- package/dist/chunk-EEODEEKX.js.map +1 -0
- package/dist/{chunk-2AQIFJHK.js → chunk-EPSCLN5W.js} +3 -3
- package/dist/{chunk-2AQIFJHK.js.map → chunk-EPSCLN5W.js.map} +1 -1
- package/dist/{chunk-AAZDYM5D.js → chunk-J3K5O6XA.js} +3 -3
- package/dist/{chunk-AAZDYM5D.js.map → chunk-J3K5O6XA.js.map} +1 -1
- package/dist/{chunk-4F2L7WPU.js → chunk-K4O6L3WH.js} +5 -3
- package/dist/chunk-K4O6L3WH.js.map +1 -0
- package/dist/{chunk-JURHZYOY.js → chunk-P6S5K7AI.js} +3 -3
- package/dist/{chunk-JURHZYOY.js.map → chunk-P6S5K7AI.js.map} +1 -1
- package/dist/{chunk-3VGQLF3N.js → chunk-RGB45PIL.js} +2 -2
- package/dist/{chunk-3VGQLF3N.js.map → chunk-RGB45PIL.js.map} +1 -1
- package/dist/{chunk-AOFJ2OKW.js → chunk-RYIWFV67.js} +2 -2
- package/dist/{chunk-AOFJ2OKW.js.map → chunk-RYIWFV67.js.map} +1 -1
- package/dist/{chunk-WOE4LPGF.js → chunk-S4R3WNRF.js} +3 -3
- package/dist/{chunk-WOE4LPGF.js.map → chunk-S4R3WNRF.js.map} +1 -1
- package/dist/{chunk-Z7KDOGKF.js → chunk-T6QGP5HN.js} +6 -6
- package/dist/{chunk-Z7KDOGKF.js.map → chunk-T6QGP5HN.js.map} +1 -1
- package/dist/{chunk-7EAJNEQ5.js → chunk-VXY6LSQ3.js} +6 -6
- package/dist/{chunk-7EAJNEQ5.js.map → chunk-VXY6LSQ3.js.map} +1 -1
- package/dist/{chunk-3H4HP733.js → chunk-W2SDSDR7.js} +23 -13
- package/dist/chunk-W2SDSDR7.js.map +1 -0
- package/dist/chunk-X5O56UO4.js +151 -0
- package/dist/chunk-X5O56UO4.js.map +1 -0
- package/dist/{chunk-RAHLV6QG.js → chunk-XAKGLR4Y.js} +6 -6
- package/dist/{chunk-RAHLV6QG.js.map → chunk-XAKGLR4Y.js.map} +1 -1
- package/dist/chunk-YROR332M.js +25 -0
- package/dist/chunk-YROR332M.js.map +1 -0
- package/dist/{chunk-YXXEHY7D.js → chunk-YUH46KA7.js} +6 -4
- package/dist/chunk-YUH46KA7.js.map +1 -0
- package/dist/cli/index.js +33 -32
- package/dist/cli/index.js.map +1 -1
- package/dist/connectors/index.js +6 -5
- package/dist/{ensure-sources-6XKA46PN.js → ensure-sources-WYXFJWUO.js} +4 -4
- package/dist/{ensure-sources-6XKA46PN.js.map → ensure-sources-WYXFJWUO.js.map} +1 -1
- package/dist/factory-assets/connectors/box.js +6 -5
- package/dist/factory-assets/connectors/deploy.js +6 -5
- package/dist/factory-assets/connectors/devserver.js +6 -5
- package/dist/factory-assets/connectors/flow/adapter.js +6 -5
- package/dist/factory-assets/connectors/flow/run-flow.js +7 -6
- package/dist/factory-assets/connectors/flow.js +6 -5
- package/dist/factory-assets/connectors/git.js +6 -5
- package/dist/factory-assets/connectors/gmail.js +6 -5
- package/dist/factory-assets/connectors/googledrive.js +6 -5
- package/dist/factory-assets/connectors/local.js +6 -5
- package/dist/factory-assets/connectors/mattermost.js +6 -5
- package/dist/factory-assets/connectors/memory.js +6 -5
- package/dist/factory-assets/connectors/minio.js +6 -5
- package/dist/factory-assets/connectors/postgres.js +6 -5
- package/dist/factory-assets/connectors/s3.js +6 -5
- package/dist/factory-assets/connectors/sharepoint.js +6 -5
- package/dist/factory-assets/connectors/sqlite.js +6 -5
- package/dist/factory-assets/connectors/static-server.js +6 -5
- package/dist/factory-assets/connectors/tunnel.js +6 -5
- package/dist/factory-assets/connectors/webdav.js +6 -5
- package/dist/factory-assets/connectors/xstate-store.js +6 -5
- package/dist/factory-assets/connectors/xstate.js +6 -5
- package/dist/{helpers-6I4SY2S7.js → helpers-TANA2HQT.js} +4 -4
- package/dist/{helpers-6I4SY2S7.js.map → helpers-TANA2HQT.js.map} +1 -1
- package/dist/{library-publish-PPNFBAVH.js → library-publish-JQNTMKZG.js} +6 -6
- package/dist/{library-publish-PPNFBAVH.js.map → library-publish-JQNTMKZG.js.map} +1 -1
- package/dist/{open-library-64LO64NE.js → open-library-NKZ4HJJ6.js} +5 -5
- package/dist/{open-library-64LO64NE.js.map → open-library-NKZ4HJJ6.js.map} +1 -1
- package/dist/{project-3UFTV7DL.js → project-AEAM2ZEW.js} +5 -5
- package/dist/{project-3UFTV7DL.js.map → project-AEAM2ZEW.js.map} +1 -1
- package/dist/runner/index.js +9 -8
- package/dist/runner/src/serve-credentials.d.ts +2 -1
- package/dist/runner/src/serve-credentials.d.ts.map +1 -1
- package/dist/runner/src/serve.d.ts.map +1 -1
- package/dist/sdk/asset-manager.js +1 -1
- package/dist/sdk/bridge.js +5 -4
- package/dist/sdk/index.js +9 -8
- package/dist/sdk/index.js.map +1 -1
- package/dist/sdk/runner.js +9 -8
- package/dist/{setup-JGXLTJ57.js → setup-Q7ACRV72.js} +10 -9
- package/dist/setup-Q7ACRV72.js.map +1 -0
- package/dist/{source-NHEYY7WH.js → source-QXQ3NO46.js} +6 -6
- package/dist/{source-NHEYY7WH.js.map → source-QXQ3NO46.js.map} +1 -1
- package/dist/{source-manifest-publish-IJLVR3IL.js → source-manifest-publish-UKWCZA2M.js} +7 -7
- package/dist/{source-manifest-publish-IJLVR3IL.js.map → source-manifest-publish-UKWCZA2M.js.map} +1 -1
- package/dist/tui/index.js +9 -8
- package/dist/tui/index.js.map +1 -1
- package/dist/workspace-plugin/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-3H4HP733.js.map +0 -1
- package/dist/chunk-3W7AOGPY.js.map +0 -1
- package/dist/chunk-4F2L7WPU.js.map +0 -1
- package/dist/chunk-D5CRFGDL.js.map +0 -1
- package/dist/chunk-YXXEHY7D.js.map +0 -1
- package/dist/setup-JGXLTJ57.js.map +0 -1
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { checkToolInputSchema } from '../../chunk-X5O56UO4.js';
|
|
2
|
+
import { entrySurface } from '../../chunk-25BOOOSM.js';
|
|
3
|
+
import { dispatchCapability } from '../../chunk-TOXPRXAK.js';
|
|
2
4
|
import { stripRunnerPrivateEnv, classifyGenericErrorMessage } from '../../chunk-BGY4KTU6.js';
|
|
3
|
-
import {
|
|
5
|
+
import { wrapAgentCommand, resolveAgentExec } from '../../chunk-YROR332M.js';
|
|
6
|
+
import { BUILTIN_DRIVER_CATALOG, AgentDriver, getBridgeLogger, registryDriverConfig, entryCredentialValue, providerCredentialEnvName } from '../../chunk-RGB45PIL.js';
|
|
4
7
|
import '../../chunk-6E6PKKAD.js';
|
|
8
|
+
import { withActivityLabelJsonSchema } from '../../chunk-QQ3G5N7X.js';
|
|
5
9
|
import '../../chunk-JMKB7IB4.js';
|
|
6
10
|
import '../../chunk-DPLIN2RA.js';
|
|
7
11
|
import { AI_PROVIDER_SURFACES, registryEntries, isEntryEnabled, parseModelRef, normalizeEntryBaseUrl, resolveEntryBaseUrl } from '../../chunk-GZZPKAV5.js';
|
|
@@ -365,6 +369,63 @@ function buildOmpToolArgs(tools) {
|
|
|
365
369
|
if (effective.length === 0) return ["--no-tools"];
|
|
366
370
|
return ["--tools", effective.join(",")];
|
|
367
371
|
}
|
|
372
|
+
var OMP_HOST_TOOL_NAME_MAX = 64;
|
|
373
|
+
function buildOmpHostTools(tools) {
|
|
374
|
+
const taken = new Set(OMP_BUILTIN_TOOLS);
|
|
375
|
+
const out = { definitions: [], capabilityNames: /* @__PURE__ */ new Map(), dropped: [] };
|
|
376
|
+
for (const tool of tools) {
|
|
377
|
+
const parameters = { ...withActivityLabelJsonSchema(tool.parameters), type: "object" };
|
|
378
|
+
const reason = checkToolInputSchema(parameters);
|
|
379
|
+
if (reason) {
|
|
380
|
+
out.dropped.push({ tool: tool.name, reason });
|
|
381
|
+
continue;
|
|
382
|
+
}
|
|
383
|
+
const base = tool.name.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, OMP_HOST_TOOL_NAME_MAX) || "capability";
|
|
384
|
+
let name = base;
|
|
385
|
+
for (let n = 2; taken.has(name); n++) {
|
|
386
|
+
const suffix = `_${n}`;
|
|
387
|
+
name = `${base.slice(0, OMP_HOST_TOOL_NAME_MAX - suffix.length)}${suffix}`;
|
|
388
|
+
}
|
|
389
|
+
taken.add(name);
|
|
390
|
+
out.capabilityNames.set(name, tool.name);
|
|
391
|
+
out.definitions.push({
|
|
392
|
+
name,
|
|
393
|
+
label: tool.name,
|
|
394
|
+
description: tool.description,
|
|
395
|
+
parameters,
|
|
396
|
+
loadMode: "essential"
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
return out;
|
|
400
|
+
}
|
|
401
|
+
var OMP_THINKING_LEVELS = [
|
|
402
|
+
"off",
|
|
403
|
+
"minimal",
|
|
404
|
+
"low",
|
|
405
|
+
"medium",
|
|
406
|
+
"high",
|
|
407
|
+
"xhigh",
|
|
408
|
+
"max",
|
|
409
|
+
"auto"
|
|
410
|
+
];
|
|
411
|
+
var OMP_MAX_IMAGE_BYTES = 5 * 1024 * 1024;
|
|
412
|
+
function ompThinkingLevel(cfg) {
|
|
413
|
+
const level = (() => {
|
|
414
|
+
if (cfg.thinking === "disabled") return "off";
|
|
415
|
+
if (cfg.effort) return cfg.effort;
|
|
416
|
+
if (cfg.thinking === "enabled") return "medium";
|
|
417
|
+
if (cfg.thinking === "adaptive") return "auto";
|
|
418
|
+
return void 0;
|
|
419
|
+
})();
|
|
420
|
+
return level !== void 0 && OMP_THINKING_LEVELS.includes(level) ? level : void 0;
|
|
421
|
+
}
|
|
422
|
+
function splitOmpModel(model) {
|
|
423
|
+
const slash = model.indexOf("/");
|
|
424
|
+
if (slash > 0 && slash < model.length - 1) {
|
|
425
|
+
return { provider: model.slice(0, slash), modelId: model.slice(slash + 1) };
|
|
426
|
+
}
|
|
427
|
+
return void 0;
|
|
428
|
+
}
|
|
368
429
|
var OmpDriver = class extends AgentDriver {
|
|
369
430
|
driverInfo = {
|
|
370
431
|
id: "omp",
|
|
@@ -383,19 +444,169 @@ var OmpDriver = class extends AgentDriver {
|
|
|
383
444
|
prevText = "";
|
|
384
445
|
/** OMP session ID captured via `get_state` after each turn. */
|
|
385
446
|
_ompSessionId;
|
|
447
|
+
/**
|
|
448
|
+
* Usage of the most recent turn, summed over every model call in it (a tool
|
|
449
|
+
* loop is one prompt but many assistant messages). Cleared when a turn
|
|
450
|
+
* starts, like claude-sdk, so it never mixes two turns.
|
|
451
|
+
*/
|
|
452
|
+
_lastTokens = null;
|
|
453
|
+
/**
|
|
454
|
+
* Prompt size of the most recent model call: the real context fill, which
|
|
455
|
+
* `_lastTokens` (turn-cumulative) overstates on a tool loop. omp's own
|
|
456
|
+
* `get_state.contextUsage.tokens` replaces it once that reply lands.
|
|
457
|
+
*/
|
|
458
|
+
_lastContextTokens = null;
|
|
459
|
+
/** Context window of the active model, from `get_state.contextUsage`. */
|
|
460
|
+
_contextWindow = null;
|
|
461
|
+
getTokenUsage() {
|
|
462
|
+
return this._lastTokens;
|
|
463
|
+
}
|
|
464
|
+
getContextTokens() {
|
|
465
|
+
return this._lastContextTokens;
|
|
466
|
+
}
|
|
467
|
+
getContextWindow() {
|
|
468
|
+
return this._contextWindow;
|
|
469
|
+
}
|
|
386
470
|
/** Per-turn settlement handlers; non-null only while a prompt is in flight. */
|
|
387
471
|
turnResolve = null;
|
|
388
472
|
turnReject = null;
|
|
473
|
+
/** omp host tool name → capability name for the last `set_host_tools` sent. */
|
|
474
|
+
hostToolCapabilities = /* @__PURE__ */ new Map();
|
|
475
|
+
/** In-flight `host_tool_call`s by omp request id; aborted by `host_tool_cancel`. */
|
|
476
|
+
hostToolCalls = /* @__PURE__ */ new Map();
|
|
477
|
+
/** Requests awaiting a `response`, by request id; failed when the process goes away. */
|
|
478
|
+
pendingRequests = /* @__PURE__ */ new Map();
|
|
479
|
+
/** Unsubscribes the capability registry listener; set while a process runs. */
|
|
480
|
+
unsubscribeToolsChanged = null;
|
|
481
|
+
/** Request ids whose failed `response` is logged by the caller, not surfaced as an error event. */
|
|
482
|
+
quietRequestIds = /* @__PURE__ */ new Set();
|
|
483
|
+
/** Capability tools already warned about, so a re-send logs each once. */
|
|
484
|
+
warnedDroppedHostTools = /* @__PURE__ */ new Set();
|
|
485
|
+
/** The `ask` (or `select` fallback) omp is parked on, until answered, cancelled or the process ends. */
|
|
486
|
+
pendingQuestion = null;
|
|
487
|
+
/**
|
|
488
|
+
* Tail of the FIFO of prompts: each `prompt()`/`promptInput()` runs only after
|
|
489
|
+
* the previous one settled, so one turn at a time is ever in flight (omp runs
|
|
490
|
+
* a single agent loop). Never rejects.
|
|
491
|
+
*/
|
|
492
|
+
promptTail = Promise.resolve();
|
|
389
493
|
get runtimeSessionId() {
|
|
390
494
|
return this._ompSessionId;
|
|
391
495
|
}
|
|
496
|
+
/** Slash commands from omp's last `available_commands_update`. */
|
|
497
|
+
cachedCommands = [];
|
|
498
|
+
getSlashCommands() {
|
|
499
|
+
return this.cachedCommands;
|
|
500
|
+
}
|
|
392
501
|
getModel() {
|
|
393
502
|
return this.config.model;
|
|
394
503
|
}
|
|
504
|
+
/**
|
|
505
|
+
* What the running omp process was last told, by config snapshot: `model`,
|
|
506
|
+
* `thinking` and `effort` are the config values those settings came from (also
|
|
507
|
+
* the rollback targets when omp rejects a change), `level` the omp thinking
|
|
508
|
+
* level sent. Set at spawn, updated on each successful `set_*`.
|
|
509
|
+
*/
|
|
510
|
+
ompApplied = {};
|
|
511
|
+
/** Serialises live reconfigure RPCs so concurrent patches never interleave. */
|
|
512
|
+
reconfigureChain = Promise.resolve();
|
|
513
|
+
/**
|
|
514
|
+
* Apply `model` / `thinking` / `effort` to this driver and, when the process
|
|
515
|
+
* is up and idle, to the running omp session (`set_model` /
|
|
516
|
+
* `set_thinking_level`). The base contract is synchronous and void, so the
|
|
517
|
+
* RPCs are fire-and-forget: a rejected change is surfaced as an `error`
|
|
518
|
+
* agent event and the config rolls back, keeping {@link getModel} honest.
|
|
519
|
+
*
|
|
520
|
+
* A patch that arrives mid-turn or before `ready` is not lost: config is the
|
|
521
|
+
* source of truth, flushed before the next `prompt()` and read by the next
|
|
522
|
+
* spawn. A model `set_model` cannot express live (no `provider/` prefix) is
|
|
523
|
+
* rejected the same way as one omp refuses: an `error` event and a rollback,
|
|
524
|
+
* since the running process cannot switch to it. In registry mode the patch
|
|
525
|
+
* also replaces `modelRef`, so a respawn (crash, `resetSession()`) starts the
|
|
526
|
+
* reconfigured model; models.yml already lists every enabled provider.
|
|
527
|
+
*/
|
|
528
|
+
reconfigure(patch) {
|
|
529
|
+
if (patch.model !== void 0) {
|
|
530
|
+
this.config.model = patch.model;
|
|
531
|
+
if (this.config.modelRef !== void 0) this.config.modelRef = patch.model;
|
|
532
|
+
}
|
|
533
|
+
if (patch.thinking !== void 0) this.config.thinking = patch.thinking;
|
|
534
|
+
if (patch.effort !== void 0) this.config.effort = patch.effort;
|
|
535
|
+
void this.syncReconfigure();
|
|
536
|
+
}
|
|
537
|
+
syncReconfigure() {
|
|
538
|
+
this.reconfigureChain = this.reconfigureChain.then(() => this.applyReconfigure());
|
|
539
|
+
return this.reconfigureChain;
|
|
540
|
+
}
|
|
541
|
+
/** Push config drift to the running process. Never rejects. */
|
|
542
|
+
async applyReconfigure() {
|
|
543
|
+
if (!this.proc || !this.ready || this.turnResolve) return;
|
|
544
|
+
const applied = this.ompApplied;
|
|
545
|
+
const model = this.config.model;
|
|
546
|
+
if (model !== void 0 && model !== applied.model) {
|
|
547
|
+
const target = splitOmpModel(model);
|
|
548
|
+
if (!target) {
|
|
549
|
+
this.log.warn("model has no provider prefix; set_model cannot apply it live", { model });
|
|
550
|
+
this.emit("agent-event", {
|
|
551
|
+
type: "error",
|
|
552
|
+
error: `set_model cannot apply "${model}" live (no provider/ prefix); model unchanged`
|
|
553
|
+
});
|
|
554
|
+
this.rollbackModel(model);
|
|
555
|
+
} else if (await this.sendReconfigure({ type: "set_model", ...target })) {
|
|
556
|
+
applied.model = model;
|
|
557
|
+
applied.modelRef = this.config.modelRef;
|
|
558
|
+
} else {
|
|
559
|
+
this.rollbackModel(model);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
await this.applyThinking();
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* Restore the model the running process holds after a failed live switch —
|
|
566
|
+
* unless a newer patch already replaced `model` (it will be applied next).
|
|
567
|
+
*/
|
|
568
|
+
rollbackModel(attempted) {
|
|
569
|
+
if (this.config.model !== attempted) return;
|
|
570
|
+
this.config.model = this.ompApplied.model;
|
|
571
|
+
this.config.modelRef = this.ompApplied.modelRef;
|
|
572
|
+
}
|
|
573
|
+
/** Push thinking/effort drift to the running process. Never rejects. */
|
|
574
|
+
async applyThinking() {
|
|
575
|
+
const applied = this.ompApplied;
|
|
576
|
+
const { thinking, effort } = this.config;
|
|
577
|
+
const level = ompThinkingLevel({ thinking, effort });
|
|
578
|
+
if (level !== void 0 && level !== applied.level) {
|
|
579
|
+
if (await this.sendReconfigure({ type: "set_thinking_level", level })) {
|
|
580
|
+
applied.level = level;
|
|
581
|
+
applied.thinking = thinking;
|
|
582
|
+
applied.effort = effort;
|
|
583
|
+
} else if (this.config.thinking === thinking && this.config.effort === effort) {
|
|
584
|
+
this.config.thinking = applied.thinking;
|
|
585
|
+
this.config.effort = applied.effort;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
/**
|
|
590
|
+
* Send one live-reconfigure request. A failed `response` is already emitted
|
|
591
|
+
* as an `error` event by {@link handleEvent}; a transport failure (timeout,
|
|
592
|
+
* process gone) is emitted here. Returns whether omp accepted it.
|
|
593
|
+
*/
|
|
594
|
+
async sendReconfigure(msg) {
|
|
595
|
+
try {
|
|
596
|
+
const resp = await this.request(msg);
|
|
597
|
+
if (resp.success) return true;
|
|
598
|
+
this.log.warn("omp rejected reconfigure", { type: msg.type, error: resp.error });
|
|
599
|
+
} catch (err) {
|
|
600
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
601
|
+
this.log.warn("reconfigure request failed", { type: msg.type, error });
|
|
602
|
+
this.emit("agent-event", { type: "error", error: `${msg.type} failed: ${error}` });
|
|
603
|
+
}
|
|
604
|
+
return false;
|
|
605
|
+
}
|
|
395
606
|
/**
|
|
396
607
|
* @param config - Driver configuration. omp-relevant fields:
|
|
397
608
|
* - `cwd` — working directory; omp session files are stored under `<cwd>/.omp/sessions/`.
|
|
398
|
-
* - `model`
|
|
609
|
+
* - `model` — forwarded as `--model <selector>`. In registry mode `modelRef` takes precedence at spawn; `reconfigure({ model })` keeps both in step.
|
|
399
610
|
* - `systemPrompt` — written to `<cwd>/.omp/system.md` and appended via `--append-system-prompt`.
|
|
400
611
|
* - `agentDir` — sets `PI_CODING_AGENT_DIR`; omp reads agent identity from this directory.
|
|
401
612
|
* - `sshKeyPath` — injected as `GIT_SSH_COMMAND` for authenticated git operations.
|
|
@@ -406,13 +617,13 @@ var OmpDriver = class extends AgentDriver {
|
|
|
406
617
|
this.config = config;
|
|
407
618
|
}
|
|
408
619
|
async start() {
|
|
409
|
-
if (this.proc) return;
|
|
410
620
|
if (this.startPromise) return this.startPromise;
|
|
621
|
+
if (this.proc) return;
|
|
411
622
|
this.startPromise = this._start();
|
|
412
623
|
return this.startPromise;
|
|
413
624
|
}
|
|
414
625
|
async _start() {
|
|
415
|
-
const args = ["--mode", "rpc"];
|
|
626
|
+
const args = ["--mode", "rpc-ui", "--no-ui"];
|
|
416
627
|
const sessionDir = path.join(this.config.cwd, ".omp", "sessions");
|
|
417
628
|
await fs.mkdir(sessionDir, { recursive: true });
|
|
418
629
|
args.push("--session-dir", sessionDir);
|
|
@@ -438,6 +649,15 @@ var OmpDriver = class extends AgentDriver {
|
|
|
438
649
|
}
|
|
439
650
|
const modelArg = providers?.modelArg ?? this.config.model;
|
|
440
651
|
if (modelArg) args.push("--model", modelArg);
|
|
652
|
+
const thinkingLevel = ompThinkingLevel(this.config);
|
|
653
|
+
if (thinkingLevel) args.push("--thinking", thinkingLevel);
|
|
654
|
+
this.ompApplied = {
|
|
655
|
+
model: this.config.model,
|
|
656
|
+
modelRef: this.config.modelRef,
|
|
657
|
+
thinking: this.config.thinking,
|
|
658
|
+
effort: this.config.effort,
|
|
659
|
+
level: thinkingLevel
|
|
660
|
+
};
|
|
441
661
|
const toolArgs = buildOmpToolArgs(this.config.tools);
|
|
442
662
|
if (toolArgs.length > 0) {
|
|
443
663
|
this.log.info("applying tool restrictions", { args: toolArgs });
|
|
@@ -465,7 +685,7 @@ var OmpDriver = class extends AgentDriver {
|
|
|
465
685
|
const overridePreArgs = process.env.OMP_BRIDGE_PREARGS ? process.env.OMP_BRIDGE_PREARGS.split(/\s+/).filter(Boolean) : [];
|
|
466
686
|
const spawnBin = overrideBin || "omp";
|
|
467
687
|
const spawnArgs = overrideBin ? [...overridePreArgs, ...args] : args;
|
|
468
|
-
|
|
688
|
+
const spawned = await new Promise((resolve, reject) => {
|
|
469
689
|
this.log.info("spawning omp", {
|
|
470
690
|
bin: spawnBin,
|
|
471
691
|
args: spawnArgs,
|
|
@@ -474,7 +694,8 @@ var OmpDriver = class extends AgentDriver {
|
|
|
474
694
|
if (env.PI_CODING_AGENT_DIR)
|
|
475
695
|
this.log.debug("env: PI_CODING_AGENT_DIR set", { value: env.PI_CODING_AGENT_DIR });
|
|
476
696
|
if (env.GIT_SSH_COMMAND) this.log.debug("env: GIT_SSH_COMMAND set");
|
|
477
|
-
const
|
|
697
|
+
const target = wrapAgentCommand(spawnBin, spawnArgs, resolveAgentExec());
|
|
698
|
+
const proc = spawn(target.command, target.args, {
|
|
478
699
|
cwd: this.config.cwd,
|
|
479
700
|
env,
|
|
480
701
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -482,6 +703,11 @@ var OmpDriver = class extends AgentDriver {
|
|
|
482
703
|
this.proc = proc;
|
|
483
704
|
const procEmitter = proc;
|
|
484
705
|
procEmitter.on("error", (err) => {
|
|
706
|
+
if (this.proc !== proc) {
|
|
707
|
+
clearTimeout(readyTimeout);
|
|
708
|
+
reject(err);
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
485
711
|
const detail = this.classifyProcessError(err);
|
|
486
712
|
this.log.error("process error", err, { detail });
|
|
487
713
|
this.emit("agent-event", { type: "error", error: detail.message, detail });
|
|
@@ -490,6 +716,12 @@ var OmpDriver = class extends AgentDriver {
|
|
|
490
716
|
});
|
|
491
717
|
procEmitter.on("exit", (code, signal) => {
|
|
492
718
|
this.log.info("process exited", { code, signal });
|
|
719
|
+
if (this.proc !== proc) {
|
|
720
|
+
clearTimeout(readyTimeout);
|
|
721
|
+
reject(new Error("omp process killed before it was ready"));
|
|
722
|
+
if (this.proc === null) this.emit("exit", { code, signal });
|
|
723
|
+
return;
|
|
724
|
+
}
|
|
493
725
|
const lastStderr = this.stderrBuffer.slice(-10).join("\n");
|
|
494
726
|
const crashed = code !== null && code !== 0;
|
|
495
727
|
if (crashed) {
|
|
@@ -532,21 +764,341 @@ var OmpDriver = class extends AgentDriver {
|
|
|
532
764
|
}
|
|
533
765
|
const startTime = Date.now();
|
|
534
766
|
const readyTimeout = setTimeout(() => {
|
|
535
|
-
if (!this.ready) {
|
|
767
|
+
if (!this.ready && this.proc === proc) {
|
|
536
768
|
this.log.warn("ready timeout, proceeding", { timeoutMs: 5e3 });
|
|
537
769
|
this.ready = true;
|
|
538
|
-
resolve();
|
|
770
|
+
resolve(proc);
|
|
539
771
|
}
|
|
540
772
|
}, 5e3);
|
|
541
773
|
this.once("ready", () => {
|
|
542
774
|
clearTimeout(readyTimeout);
|
|
543
|
-
if (!this.ready) {
|
|
775
|
+
if (!this.ready && this.proc === proc) {
|
|
544
776
|
this.log.info("process ready", { elapsedMs: Date.now() - startTime });
|
|
545
777
|
this.ready = true;
|
|
546
|
-
resolve();
|
|
778
|
+
resolve(proc);
|
|
547
779
|
}
|
|
548
780
|
});
|
|
549
781
|
});
|
|
782
|
+
const assertCurrent = () => {
|
|
783
|
+
if (this.proc !== spawned) throw new Error("omp process was killed during start");
|
|
784
|
+
};
|
|
785
|
+
assertCurrent();
|
|
786
|
+
const hooks = this.config.capabilities;
|
|
787
|
+
if (hooks) {
|
|
788
|
+
this.unsubscribeToolsChanged = hooks.onToolsChanged?.(() => {
|
|
789
|
+
void this.syncHostTools();
|
|
790
|
+
}) ?? null;
|
|
791
|
+
}
|
|
792
|
+
await Promise.all([this.enableAskDialog(), hooks ? this.syncHostTools() : void 0]);
|
|
793
|
+
assertCurrent();
|
|
794
|
+
void this.captureState({ announceSession: false });
|
|
795
|
+
}
|
|
796
|
+
/**
|
|
797
|
+
* Register the runner's capabilities with omp as host tools.
|
|
798
|
+
*
|
|
799
|
+
* Sends the full set every time: `set_host_tools` replaces omp's previous
|
|
800
|
+
* host-owned set, so a registry change that removes a capability takes
|
|
801
|
+
* effect too. Best-effort — a failure is logged and the session runs
|
|
802
|
+
* without host tools rather than failing to start.
|
|
803
|
+
*/
|
|
804
|
+
async syncHostTools() {
|
|
805
|
+
const hooks = this.config.capabilities;
|
|
806
|
+
if (!hooks || !this.proc) return;
|
|
807
|
+
const set = buildOmpHostTools(hooks.composeTools());
|
|
808
|
+
for (const { tool, reason } of set.dropped) {
|
|
809
|
+
const key = `${tool}\0${reason}`;
|
|
810
|
+
if (this.warnedDroppedHostTools.has(key)) continue;
|
|
811
|
+
this.warnedDroppedHostTools.add(key);
|
|
812
|
+
this.log.warn("host tool dropped: invalid input schema", { tool, reason });
|
|
813
|
+
}
|
|
814
|
+
this.hostToolCapabilities = set.capabilityNames;
|
|
815
|
+
try {
|
|
816
|
+
const response = await this.request(
|
|
817
|
+
{ type: "set_host_tools", tools: set.definitions },
|
|
818
|
+
{ quiet: true }
|
|
819
|
+
);
|
|
820
|
+
if (response.success) {
|
|
821
|
+
const data = response.data;
|
|
822
|
+
this.log.info("registered omp host tools", { toolNames: data?.toolNames });
|
|
823
|
+
} else {
|
|
824
|
+
this.log.error("omp rejected host tools", new Error(response.error ?? "unknown error"), {
|
|
825
|
+
tools: set.definitions.map((t) => t.name)
|
|
826
|
+
});
|
|
827
|
+
}
|
|
828
|
+
} catch (err) {
|
|
829
|
+
this.log.error("registering omp host tools failed", err);
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
/**
|
|
833
|
+
* Execute a capability omp asked the host to run (`host_tool_call`) and
|
|
834
|
+
* answer with `host_tool_result`. Goes through {@link dispatchCapability}
|
|
835
|
+
* so validation, fire-and-forget and render semantics match claude-sdk.
|
|
836
|
+
*
|
|
837
|
+
* Emits `tool_call` / `tool_execution_end` around the dispatch: the
|
|
838
|
+
* normalizer does not read omp's own tool frames, so without these the
|
|
839
|
+
* call — and its `activity_label` — would never reach the chat.
|
|
840
|
+
*/
|
|
841
|
+
handleHostToolCall(event) {
|
|
842
|
+
const id = event.id;
|
|
843
|
+
if (typeof id !== "string") return;
|
|
844
|
+
const hostName = typeof event.toolName === "string" ? event.toolName : "";
|
|
845
|
+
const name = this.hostToolCapabilities.get(hostName) ?? hostName;
|
|
846
|
+
const callId = typeof event.toolCallId === "string" ? event.toolCallId : id;
|
|
847
|
+
const input = event.arguments ?? {};
|
|
848
|
+
const hooks = this.config.capabilities;
|
|
849
|
+
const controller = new AbortController();
|
|
850
|
+
const call = { controller, name };
|
|
851
|
+
this.hostToolCalls.set(id, call);
|
|
852
|
+
this.emit("agent-event", {
|
|
853
|
+
type: "tool_call",
|
|
854
|
+
name,
|
|
855
|
+
tool: { name },
|
|
856
|
+
toolCallId: callId,
|
|
857
|
+
input
|
|
858
|
+
});
|
|
859
|
+
void (async () => {
|
|
860
|
+
let text;
|
|
861
|
+
let isError = false;
|
|
862
|
+
try {
|
|
863
|
+
if (!hooks) throw new Error(`no capability host for ${name}`);
|
|
864
|
+
const dispatch = await dispatchCapability(
|
|
865
|
+
hooks,
|
|
866
|
+
callId,
|
|
867
|
+
name,
|
|
868
|
+
input,
|
|
869
|
+
() => this.log.warn("background capability handler failed", {
|
|
870
|
+
name,
|
|
871
|
+
callId
|
|
872
|
+
// Nothing from the error: its message can quote the call's content.
|
|
873
|
+
}),
|
|
874
|
+
controller.signal
|
|
875
|
+
);
|
|
876
|
+
text = typeof dispatch.result === "string" ? dispatch.result : JSON.stringify(dispatch.result ?? {});
|
|
877
|
+
} catch (err) {
|
|
878
|
+
isError = true;
|
|
879
|
+
text = `Error: ${err?.message ?? String(err)}`;
|
|
880
|
+
}
|
|
881
|
+
if (this.hostToolCalls.get(id) !== call) return;
|
|
882
|
+
this.hostToolCalls.delete(id);
|
|
883
|
+
this.emit("agent-event", { type: "tool_execution_end", toolName: name });
|
|
884
|
+
try {
|
|
885
|
+
this.send({
|
|
886
|
+
type: "host_tool_result",
|
|
887
|
+
id,
|
|
888
|
+
result: { content: [{ type: "text", text }] },
|
|
889
|
+
...isError ? { isError: true } : {}
|
|
890
|
+
});
|
|
891
|
+
} catch (err) {
|
|
892
|
+
this.log.warn("host tool result undeliverable", { name, callId, error: String(err) });
|
|
893
|
+
}
|
|
894
|
+
})();
|
|
895
|
+
}
|
|
896
|
+
/**
|
|
897
|
+
* `host_tool_cancel`: omp aborted the call, so abort the capability handler
|
|
898
|
+
* and close the call's chat activity (the handler's later settlement is
|
|
899
|
+
* ignored, so this is the only `tool_execution_end` the call gets).
|
|
900
|
+
*/
|
|
901
|
+
handleHostToolCancel(event) {
|
|
902
|
+
const targetId = event.targetId;
|
|
903
|
+
if (typeof targetId !== "string") return;
|
|
904
|
+
this.abortHostToolCall(targetId);
|
|
905
|
+
}
|
|
906
|
+
/** Abort one in-flight host tool call and end its activity; no-op if already settled. */
|
|
907
|
+
abortHostToolCall(id) {
|
|
908
|
+
const call = this.hostToolCalls.get(id);
|
|
909
|
+
if (!call) return;
|
|
910
|
+
this.hostToolCalls.delete(id);
|
|
911
|
+
call.controller.abort();
|
|
912
|
+
this.emit("agent-event", { type: "tool_execution_end", toolName: call.name });
|
|
913
|
+
}
|
|
914
|
+
// ── Interactive questions (`ask`) ──────────────────────────────────────────
|
|
915
|
+
/**
|
|
916
|
+
* `extension_ui_request`: omp asks the host something. Only `ask` (and the
|
|
917
|
+
* `select` omp falls back to when `set_ask_dialog` is unavailable) can carry
|
|
918
|
+
* a user question; both park until {@link answerQuestion}. Presentation
|
|
919
|
+
* frames expect no reply. Every other kind is a dialog nobody here can
|
|
920
|
+
* answer, so it is cancelled at once — an unanswered dialog would leave the
|
|
921
|
+
* tool call, and the turn, waiting forever.
|
|
922
|
+
*/
|
|
923
|
+
handleExtensionUiRequest(event) {
|
|
924
|
+
const method = event.method;
|
|
925
|
+
if (method === "cancel") {
|
|
926
|
+
if (typeof event.targetId === "string" && this.pendingQuestion?.id === event.targetId) {
|
|
927
|
+
this.pendingQuestion = null;
|
|
928
|
+
}
|
|
929
|
+
return;
|
|
930
|
+
}
|
|
931
|
+
if (method === "notify" || method === "setStatus" || method === "setWidget" || method === "setTitle" || method === "set_editor_text" || method === "open_url") {
|
|
932
|
+
return;
|
|
933
|
+
}
|
|
934
|
+
const id = event.id;
|
|
935
|
+
if (typeof id !== "string") return;
|
|
936
|
+
let parsed = null;
|
|
937
|
+
if (method === "ask") parsed = this.parseAskRequest(id, event);
|
|
938
|
+
else if (method === "select") parsed = this.parseSelectRequest(id, event);
|
|
939
|
+
if (!parsed) {
|
|
940
|
+
this.log.debug("cancelling unsupported omp dialog", { method: String(method) });
|
|
941
|
+
this.sendUiResponse({ id, cancelled: true });
|
|
942
|
+
return;
|
|
943
|
+
}
|
|
944
|
+
this.cancelPendingQuestion();
|
|
945
|
+
this.pendingQuestion = parsed;
|
|
946
|
+
this.announceQuestion(parsed, event);
|
|
947
|
+
}
|
|
948
|
+
parseAskRequest(id, event) {
|
|
949
|
+
if (!Array.isArray(event.questions) || event.questions.length === 0) return null;
|
|
950
|
+
const questions = [];
|
|
951
|
+
for (const raw of event.questions) {
|
|
952
|
+
const q = raw;
|
|
953
|
+
if (!q || typeof q.id !== "string" || typeof q.question !== "string" || !q.question) {
|
|
954
|
+
return null;
|
|
955
|
+
}
|
|
956
|
+
const options = (Array.isArray(q.options) ? q.options : []).flatMap((o) => {
|
|
957
|
+
let label = o;
|
|
958
|
+
if (o && typeof o === "object" && "label" in o) label = o.label;
|
|
959
|
+
return typeof label === "string" ? [label] : [];
|
|
960
|
+
});
|
|
961
|
+
questions.push({ id: q.id, question: q.question, options, multi: q.multi === true });
|
|
962
|
+
}
|
|
963
|
+
return { id, method: "ask", questions, answers: questions.map(() => void 0) };
|
|
964
|
+
}
|
|
965
|
+
parseSelectRequest(id, event) {
|
|
966
|
+
if (typeof event.title !== "string" || !event.title || !Array.isArray(event.options)) {
|
|
967
|
+
return null;
|
|
968
|
+
}
|
|
969
|
+
const options = event.options.filter((o) => typeof o === "string");
|
|
970
|
+
if (options.length === 0) return null;
|
|
971
|
+
return {
|
|
972
|
+
id,
|
|
973
|
+
method: "select",
|
|
974
|
+
questions: [{ id, question: event.title, options, multi: false }],
|
|
975
|
+
answers: [void 0]
|
|
976
|
+
};
|
|
977
|
+
}
|
|
978
|
+
/**
|
|
979
|
+
* Publish the parked question the way claude-sdk does for `AskUserQuestion`:
|
|
980
|
+
* an assistant `tool_use` block the normalizer turns into one `question`
|
|
981
|
+
* event per question, plus the matching `tool_call`. Option descriptions and
|
|
982
|
+
* `header`s survive in the tool input for consumers that render them.
|
|
983
|
+
*/
|
|
984
|
+
announceQuestion(pending, event) {
|
|
985
|
+
const rawQuestions = Array.isArray(event.questions) ? event.questions : [];
|
|
986
|
+
const input = {
|
|
987
|
+
requestId: pending.id,
|
|
988
|
+
questions: pending.questions.map((q, i) => {
|
|
989
|
+
const raw = rawQuestions[i];
|
|
990
|
+
return {
|
|
991
|
+
question: q.question,
|
|
992
|
+
...typeof raw?.header === "string" ? { header: raw.header } : {},
|
|
993
|
+
multiSelect: q.multi,
|
|
994
|
+
options: q.options.map((label, j) => {
|
|
995
|
+
const description = raw?.options?.[j]?.description;
|
|
996
|
+
return { label, ...typeof description === "string" ? { description } : {} };
|
|
997
|
+
})
|
|
998
|
+
};
|
|
999
|
+
})
|
|
1000
|
+
};
|
|
1001
|
+
const toolCallId = `omp-ask:${pending.id}`;
|
|
1002
|
+
this.emit("agent-event", {
|
|
1003
|
+
type: "message_start",
|
|
1004
|
+
message: {
|
|
1005
|
+
role: "assistant",
|
|
1006
|
+
content: [{ type: "tool_use", name: "AskUserQuestion", id: toolCallId, input }]
|
|
1007
|
+
}
|
|
1008
|
+
});
|
|
1009
|
+
this.emit("agent-event", {
|
|
1010
|
+
type: "tool_call",
|
|
1011
|
+
name: "AskUserQuestion",
|
|
1012
|
+
tool: { name: "AskUserQuestion" },
|
|
1013
|
+
toolCallId,
|
|
1014
|
+
input
|
|
1015
|
+
});
|
|
1016
|
+
this.log.debug("paused on omp ask", { questions: pending.questions.length });
|
|
1017
|
+
}
|
|
1018
|
+
hasPendingQuestion() {
|
|
1019
|
+
return this.pendingQuestion !== null;
|
|
1020
|
+
}
|
|
1021
|
+
/**
|
|
1022
|
+
* While omp is parked on a question a reply that is not an answer must not
|
|
1023
|
+
* become a prompt: the turn is still running, and a second prompt would
|
|
1024
|
+
* collide with it.
|
|
1025
|
+
*/
|
|
1026
|
+
get acceptsReplyAsPrompt() {
|
|
1027
|
+
return this.pendingQuestion === null;
|
|
1028
|
+
}
|
|
1029
|
+
answerQuestion(answer, question, requestId) {
|
|
1030
|
+
const pending = this.pendingQuestion;
|
|
1031
|
+
if (!pending || typeof answer !== "string") return false;
|
|
1032
|
+
if (requestId !== void 0 && requestId !== pending.id) return false;
|
|
1033
|
+
let index = question !== void 0 ? pending.questions.findIndex((q) => q.question === question) : -1;
|
|
1034
|
+
if (index === -1) index = pending.answers.findIndex((a) => a === void 0);
|
|
1035
|
+
if (index === -1) return false;
|
|
1036
|
+
pending.answers[index] = answer;
|
|
1037
|
+
if (pending.answers.some((a) => a === void 0)) return true;
|
|
1038
|
+
this.pendingQuestion = null;
|
|
1039
|
+
this.sendUiResponse(this.buildQuestionResponse(pending));
|
|
1040
|
+
this.log.debug("answered omp ask", { questions: pending.questions.length });
|
|
1041
|
+
return true;
|
|
1042
|
+
}
|
|
1043
|
+
/** Shape the collected answers as the `extension_ui_response` payload for the request's method. */
|
|
1044
|
+
buildQuestionResponse(pending) {
|
|
1045
|
+
const find = (options, text) => options.find((o) => o === text) ?? options.find((o) => o.toLowerCase() === text.toLowerCase());
|
|
1046
|
+
if (pending.method === "select") {
|
|
1047
|
+
const match = find(pending.questions[0].options, (pending.answers[0] ?? "").trim());
|
|
1048
|
+
if (match !== void 0) return { id: pending.id, value: match };
|
|
1049
|
+
this.log.warn("select answer matches no option; cancelling it");
|
|
1050
|
+
return { id: pending.id, cancelled: true };
|
|
1051
|
+
}
|
|
1052
|
+
const answers = pending.questions.map((q, i) => {
|
|
1053
|
+
const text = (pending.answers[i] ?? "").trim();
|
|
1054
|
+
const whole = find(q.options, text);
|
|
1055
|
+
if (whole !== void 0) return { id: q.id, selectedOptions: [whole] };
|
|
1056
|
+
if (q.multi) {
|
|
1057
|
+
const parts = text.split(",").map((p) => p.trim()).filter(Boolean);
|
|
1058
|
+
const matched = parts.map((p) => find(q.options, p));
|
|
1059
|
+
if (parts.length > 0 && matched.every((m) => m !== void 0)) {
|
|
1060
|
+
return { id: q.id, selectedOptions: [...new Set(matched)] };
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
return { id: q.id, selectedOptions: [], ...text ? { customInput: text } : {} };
|
|
1064
|
+
});
|
|
1065
|
+
return { id: pending.id, answers };
|
|
1066
|
+
}
|
|
1067
|
+
/** Write an `extension_ui_response`; undeliverable (process gone) is logged, not thrown. */
|
|
1068
|
+
sendUiResponse(payload) {
|
|
1069
|
+
try {
|
|
1070
|
+
this.send({ type: "extension_ui_response", ...payload });
|
|
1071
|
+
} catch (err) {
|
|
1072
|
+
this.log.warn("extension ui response undeliverable", { error: String(err) });
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
/** Drop the pending question and tell omp it was cancelled, so its tool call unwinds. */
|
|
1076
|
+
cancelPendingQuestion() {
|
|
1077
|
+
const pending = this.pendingQuestion;
|
|
1078
|
+
if (!pending) return;
|
|
1079
|
+
this.pendingQuestion = null;
|
|
1080
|
+
this.sendUiResponse({ id: pending.id, cancelled: true });
|
|
1081
|
+
}
|
|
1082
|
+
/**
|
|
1083
|
+
* Opt in to omp's single `ask` dialog request (off by default per process).
|
|
1084
|
+
* Best-effort: a build without the command answers with a failed response and
|
|
1085
|
+
* its `ask` keeps degrading to one `select` per question, which
|
|
1086
|
+
* {@link handleExtensionUiRequest} still surfaces as a question.
|
|
1087
|
+
*/
|
|
1088
|
+
async enableAskDialog() {
|
|
1089
|
+
try {
|
|
1090
|
+
const response = await this.request(
|
|
1091
|
+
{ type: "set_ask_dialog", enabled: true },
|
|
1092
|
+
{ quiet: true }
|
|
1093
|
+
);
|
|
1094
|
+
if (!response.success) {
|
|
1095
|
+
this.log.warn("omp rejected set_ask_dialog; ask falls back to select", {
|
|
1096
|
+
error: response.error
|
|
1097
|
+
});
|
|
1098
|
+
}
|
|
1099
|
+
} catch (err) {
|
|
1100
|
+
this.log.warn("set_ask_dialog failed", { error: String(err) });
|
|
1101
|
+
}
|
|
550
1102
|
}
|
|
551
1103
|
extractMessageText(msg) {
|
|
552
1104
|
if (!msg) return "";
|
|
@@ -556,19 +1108,59 @@ var OmpDriver = class extends AgentDriver {
|
|
|
556
1108
|
return c.filter((b) => b.type === "text" && b.text).map((b) => b.text).join("");
|
|
557
1109
|
return "";
|
|
558
1110
|
}
|
|
1111
|
+
/**
|
|
1112
|
+
* `available_commands_update`: replace the cached slash-command list and
|
|
1113
|
+
* publish it. Names carry no leading slash (omp's already don't), matching
|
|
1114
|
+
* claude-sdk's `commands_available`. Entries without a name are skipped.
|
|
1115
|
+
*/
|
|
1116
|
+
handleCommandsUpdate(event) {
|
|
1117
|
+
const raw = Array.isArray(event.commands) ? event.commands : [];
|
|
1118
|
+
const commands = [];
|
|
1119
|
+
for (const entry of raw) {
|
|
1120
|
+
if (!entry || typeof entry !== "object") continue;
|
|
1121
|
+
const c = entry;
|
|
1122
|
+
if (typeof c.name !== "string" || !c.name) continue;
|
|
1123
|
+
const hint = c.input && typeof c.input === "object" ? c.input.hint : void 0;
|
|
1124
|
+
commands.push({
|
|
1125
|
+
name: c.name,
|
|
1126
|
+
description: typeof c.description === "string" ? c.description : "",
|
|
1127
|
+
argumentHint: typeof hint === "string" && hint ? hint : void 0
|
|
1128
|
+
});
|
|
1129
|
+
}
|
|
1130
|
+
this.cachedCommands = commands;
|
|
1131
|
+
this.emit("agent-event", { type: "commands_available", commands });
|
|
1132
|
+
this.log.debug("discovered slash commands", { count: commands.length });
|
|
1133
|
+
}
|
|
559
1134
|
handleEvent(event) {
|
|
560
1135
|
if (event.type === "ready") {
|
|
561
1136
|
this.emit("ready");
|
|
562
1137
|
return;
|
|
563
1138
|
}
|
|
564
1139
|
if (event.type === "response") {
|
|
565
|
-
|
|
1140
|
+
const quiet = typeof event.id === "string" && this.quietRequestIds.delete(event.id);
|
|
1141
|
+
if (!event.success && event.error && !quiet) {
|
|
566
1142
|
const detail = this.classifyErrorMessage(event.error);
|
|
567
1143
|
this.emit("agent-event", { type: "error", error: event.error, detail });
|
|
568
1144
|
}
|
|
569
1145
|
this.emit(`response:${event.id}`, event);
|
|
570
1146
|
return;
|
|
571
1147
|
}
|
|
1148
|
+
if (event.type === "host_tool_call") {
|
|
1149
|
+
this.handleHostToolCall(event);
|
|
1150
|
+
return;
|
|
1151
|
+
}
|
|
1152
|
+
if (event.type === "host_tool_cancel") {
|
|
1153
|
+
this.handleHostToolCancel(event);
|
|
1154
|
+
return;
|
|
1155
|
+
}
|
|
1156
|
+
if (event.type === "extension_ui_request") {
|
|
1157
|
+
this.handleExtensionUiRequest(event);
|
|
1158
|
+
return;
|
|
1159
|
+
}
|
|
1160
|
+
if (event.type === "available_commands_update") {
|
|
1161
|
+
this.handleCommandsUpdate(event);
|
|
1162
|
+
return;
|
|
1163
|
+
}
|
|
572
1164
|
if (event.type === "error" && event.error) {
|
|
573
1165
|
const detail = this.classifyErrorMessage(event.error);
|
|
574
1166
|
this.emit("agent-event", { ...event, detail });
|
|
@@ -583,7 +1175,13 @@ var OmpDriver = class extends AgentDriver {
|
|
|
583
1175
|
delta = text;
|
|
584
1176
|
}
|
|
585
1177
|
this.prevText = text;
|
|
586
|
-
|
|
1178
|
+
const sub = event.assistantMessageEvent;
|
|
1179
|
+
const thinking = sub && typeof sub === "object" && "type" in sub && sub.type === "thinking_delta" ? "delta" in sub && typeof sub.delta === "string" ? sub.delta : "" : "";
|
|
1180
|
+
this.emit("agent-event", {
|
|
1181
|
+
...event,
|
|
1182
|
+
_textDelta: delta,
|
|
1183
|
+
...thinking ? { _thinkingDelta: thinking } : {}
|
|
1184
|
+
});
|
|
587
1185
|
return;
|
|
588
1186
|
}
|
|
589
1187
|
if (event.type === "message_start") {
|
|
@@ -592,6 +1190,7 @@ var OmpDriver = class extends AgentDriver {
|
|
|
592
1190
|
if (event.type === "message_end" || event.type === "agent_end") {
|
|
593
1191
|
this.prevText = "";
|
|
594
1192
|
}
|
|
1193
|
+
if (event.type === "message_end") this.recordMessageUsage(event.message);
|
|
595
1194
|
if (event.type === "message_end" && event.message?.role === "assistant" && event.message.stopReason === "error") {
|
|
596
1195
|
const error = event.message.errorMessage || "omp request failed";
|
|
597
1196
|
const detail = this.classifyErrorMessage(error);
|
|
@@ -599,7 +1198,7 @@ var OmpDriver = class extends AgentDriver {
|
|
|
599
1198
|
this.emit("agent-event", { type: "error", error, detail });
|
|
600
1199
|
}
|
|
601
1200
|
if (event.type === "agent_end") {
|
|
602
|
-
void this.
|
|
1201
|
+
void this.captureState();
|
|
603
1202
|
}
|
|
604
1203
|
this.emit("agent-event", event);
|
|
605
1204
|
if (event.type === "agent_end") {
|
|
@@ -627,31 +1226,23 @@ var OmpDriver = class extends AgentDriver {
|
|
|
627
1226
|
reject?.(err);
|
|
628
1227
|
}
|
|
629
1228
|
/**
|
|
630
|
-
* Query OMP
|
|
631
|
-
*
|
|
632
|
-
*
|
|
1229
|
+
* Query OMP's current state via the `get_state` RPC.
|
|
1230
|
+
*
|
|
1231
|
+
* Always refreshes the context fill from `contextUsage`. With
|
|
1232
|
+
* `announceSession` (the default, used after each turn) it also records the
|
|
1233
|
+
* native session ID and emits a `session_info` event so the forge layer can
|
|
1234
|
+
* persist it. Failures are silently swallowed — both are best-effort.
|
|
633
1235
|
*/
|
|
634
|
-
async
|
|
1236
|
+
async captureState(options = {}) {
|
|
1237
|
+
const announceSession = options.announceSession ?? true;
|
|
635
1238
|
try {
|
|
636
|
-
const
|
|
637
|
-
const response = await new Promise((resolve, reject) => {
|
|
638
|
-
const timer = setTimeout(() => reject(new Error("get_state timeout")), 5e3);
|
|
639
|
-
this.once(`response:${id}`, (resp) => {
|
|
640
|
-
clearTimeout(timer);
|
|
641
|
-
resolve(resp);
|
|
642
|
-
});
|
|
643
|
-
try {
|
|
644
|
-
this.send({ id, type: "get_state" });
|
|
645
|
-
} catch (err) {
|
|
646
|
-
clearTimeout(timer);
|
|
647
|
-
reject(err);
|
|
648
|
-
}
|
|
649
|
-
});
|
|
1239
|
+
const response = await this.request({ type: "get_state" }, { quiet: !announceSession });
|
|
650
1240
|
if (response.success && response.data) {
|
|
651
1241
|
const data = response.data;
|
|
1242
|
+
this.captureContextUsage(data.contextUsage);
|
|
652
1243
|
const sessionId = data.sessionId;
|
|
653
1244
|
const sessionFile = data.sessionFile;
|
|
654
|
-
if (sessionId) {
|
|
1245
|
+
if (announceSession && sessionId) {
|
|
655
1246
|
this._ompSessionId = sessionId;
|
|
656
1247
|
this.log.debug("omp session id assigned", { sessionId });
|
|
657
1248
|
this.emit("agent-event", {
|
|
@@ -664,9 +1255,99 @@ var OmpDriver = class extends AgentDriver {
|
|
|
664
1255
|
} catch {
|
|
665
1256
|
}
|
|
666
1257
|
}
|
|
1258
|
+
/** `get_state.contextUsage` → context fill + window; absent or malformed values are ignored. */
|
|
1259
|
+
captureContextUsage(raw) {
|
|
1260
|
+
if (!raw || typeof raw !== "object") return;
|
|
1261
|
+
const tokens = "tokens" in raw ? raw.tokens : void 0;
|
|
1262
|
+
const contextWindow = "contextWindow" in raw ? raw.contextWindow : void 0;
|
|
1263
|
+
if (typeof tokens === "number" && Number.isFinite(tokens) && tokens >= 0) {
|
|
1264
|
+
this._lastContextTokens = tokens;
|
|
1265
|
+
}
|
|
1266
|
+
if (typeof contextWindow === "number" && Number.isFinite(contextWindow) && contextWindow > 0) {
|
|
1267
|
+
this._contextWindow = contextWindow;
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
/** Forget the previous turn's usage; called as a new turn begins. */
|
|
1271
|
+
beginUsageTurn() {
|
|
1272
|
+
this._lastTokens = null;
|
|
1273
|
+
this._lastContextTokens = null;
|
|
1274
|
+
}
|
|
1275
|
+
/**
|
|
1276
|
+
* Fold one finished assistant message into the turn's usage. Only the
|
|
1277
|
+
* `message_end` value is final (`message_start` and partials carry running
|
|
1278
|
+
* zeros). A message without usage, or an errored one reporting all zeros,
|
|
1279
|
+
* bills nothing and must neither create a reading nor wipe a good one.
|
|
1280
|
+
*/
|
|
1281
|
+
recordMessageUsage(message) {
|
|
1282
|
+
if (message?.role !== "assistant" || !message.usage) return;
|
|
1283
|
+
const count = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
|
|
1284
|
+
const input = count(message.usage.input);
|
|
1285
|
+
const output = count(message.usage.output);
|
|
1286
|
+
const cacheRead = count(message.usage.cacheRead);
|
|
1287
|
+
const cacheWrite = count(message.usage.cacheWrite);
|
|
1288
|
+
const reasoning = count(message.usage.reasoningTokens);
|
|
1289
|
+
const total = count(message.usage.totalTokens);
|
|
1290
|
+
const callContext = (input ?? 0) + (cacheRead ?? 0) + (cacheWrite ?? 0);
|
|
1291
|
+
if (callContext + (output ?? 0) + (total ?? 0) === 0) return;
|
|
1292
|
+
const turn = { ...this._lastTokens };
|
|
1293
|
+
const add = (key, value) => {
|
|
1294
|
+
if (value !== void 0) turn[key] = (turn[key] ?? 0) + value;
|
|
1295
|
+
};
|
|
1296
|
+
add("inputTokens", input);
|
|
1297
|
+
add("outputTokens", output);
|
|
1298
|
+
add("cacheReadTokens", cacheRead);
|
|
1299
|
+
add("cacheCreationTokens", cacheWrite);
|
|
1300
|
+
add("reasoningTokens", reasoning);
|
|
1301
|
+
add("totalTokens", total);
|
|
1302
|
+
this._lastTokens = turn;
|
|
1303
|
+
if (callContext > 0) this._lastContextTokens = callContext;
|
|
1304
|
+
}
|
|
667
1305
|
nextId() {
|
|
668
1306
|
return `req-${++this.reqId}`;
|
|
669
1307
|
}
|
|
1308
|
+
/**
|
|
1309
|
+
* Send a command and await its `response` frame.
|
|
1310
|
+
*
|
|
1311
|
+
* @param options.quiet - Leave a failed response to the caller instead of
|
|
1312
|
+
* surfacing it as an `error` agent event.
|
|
1313
|
+
* @throws When the process is not running or no response arrives within
|
|
1314
|
+
* `options.timeoutMs` (default 5 s).
|
|
1315
|
+
*/
|
|
1316
|
+
request(msg, options = {}) {
|
|
1317
|
+
const id = this.nextId();
|
|
1318
|
+
const event = `response:${id}`;
|
|
1319
|
+
let resolve;
|
|
1320
|
+
let reject;
|
|
1321
|
+
const promise = new Promise((res, rej) => {
|
|
1322
|
+
resolve = res;
|
|
1323
|
+
reject = rej;
|
|
1324
|
+
});
|
|
1325
|
+
const onResponse = (resp) => {
|
|
1326
|
+
clearTimeout(timer);
|
|
1327
|
+
this.pendingRequests.delete(id);
|
|
1328
|
+
resolve(resp);
|
|
1329
|
+
};
|
|
1330
|
+
const fail = (err, keepQuiet = false) => {
|
|
1331
|
+
clearTimeout(timer);
|
|
1332
|
+
this.pendingRequests.delete(id);
|
|
1333
|
+
this.removeListener(event, onResponse);
|
|
1334
|
+
if (!keepQuiet) this.quietRequestIds.delete(id);
|
|
1335
|
+
reject(err);
|
|
1336
|
+
};
|
|
1337
|
+
const timer = setTimeout(
|
|
1338
|
+
() => fail(new Error(`${msg.type} timeout`), true),
|
|
1339
|
+
options.timeoutMs ?? 5e3
|
|
1340
|
+
);
|
|
1341
|
+
this.once(event, onResponse);
|
|
1342
|
+
this.pendingRequests.set(id, fail);
|
|
1343
|
+
if (options.quiet) this.quietRequestIds.add(id);
|
|
1344
|
+
try {
|
|
1345
|
+
this.send({ id, ...msg });
|
|
1346
|
+
} catch (err) {
|
|
1347
|
+
fail(err);
|
|
1348
|
+
}
|
|
1349
|
+
return promise;
|
|
1350
|
+
}
|
|
670
1351
|
send(msg) {
|
|
671
1352
|
if (!this.proc?.stdin?.writable) {
|
|
672
1353
|
const detail = {
|
|
@@ -694,15 +1375,94 @@ var OmpDriver = class extends AgentDriver {
|
|
|
694
1375
|
* @throws {Error} When the omp process is not running, its stdin is closed, or
|
|
695
1376
|
* the child crashes/exits before the turn completes.
|
|
696
1377
|
*/
|
|
697
|
-
|
|
1378
|
+
prompt(message) {
|
|
1379
|
+
return this.enqueuePrompt(() => this.runPrompt({ message }));
|
|
1380
|
+
}
|
|
1381
|
+
/**
|
|
1382
|
+
* Run one prompt after every earlier one settled. A question omp is parked on
|
|
1383
|
+
* is cancelled first, synchronously and ahead of the queue: the parked turn
|
|
1384
|
+
* can only finish once its `ask` is released, so the new prompt (the user
|
|
1385
|
+
* typing instead of answering) must not wait behind it. The runner does not
|
|
1386
|
+
* serialise `prompt` commands, so the driver does, as claude-sdk does.
|
|
1387
|
+
*/
|
|
1388
|
+
enqueuePrompt(run) {
|
|
1389
|
+
this.cancelPendingQuestion();
|
|
1390
|
+
const queued = this.promptTail.then(run);
|
|
1391
|
+
this.promptTail = queued.then(
|
|
1392
|
+
() => void 0,
|
|
1393
|
+
() => void 0
|
|
1394
|
+
);
|
|
1395
|
+
return queued;
|
|
1396
|
+
}
|
|
1397
|
+
/**
|
|
1398
|
+
* Structured prompt: text plus image/file/skill attachments. Images travel as
|
|
1399
|
+
* omp `ImageContent` (`prompt.images`, base64 + mimeType); file and skill
|
|
1400
|
+
* attachments are named in a text preamble, because omp reads files itself.
|
|
1401
|
+
* Turn settlement is shared with {@link prompt}.
|
|
1402
|
+
*/
|
|
1403
|
+
promptInput(input) {
|
|
1404
|
+
return this.enqueuePrompt(async () => this.runPrompt(await this.buildPromptPayload(input)));
|
|
1405
|
+
}
|
|
1406
|
+
/** Resolve attachments into the `message` + `images` fields of an omp `prompt` frame. */
|
|
1407
|
+
async buildPromptPayload(input) {
|
|
1408
|
+
const attachments = input.attachments ?? [];
|
|
1409
|
+
if (attachments.length === 0) return { message: input.text };
|
|
1410
|
+
const mimeByExt = {
|
|
1411
|
+
".png": "image/png",
|
|
1412
|
+
".jpg": "image/jpeg",
|
|
1413
|
+
".jpeg": "image/jpeg",
|
|
1414
|
+
".gif": "image/gif",
|
|
1415
|
+
".webp": "image/webp"
|
|
1416
|
+
};
|
|
1417
|
+
const images = [];
|
|
1418
|
+
const preamble = [];
|
|
1419
|
+
let root;
|
|
1420
|
+
for (const attachment of attachments) {
|
|
1421
|
+
if (attachment.type !== "image") {
|
|
1422
|
+
preamble.push(`[Attached ${attachment.type}: ${attachment.name} (${attachment.path})]`);
|
|
1423
|
+
continue;
|
|
1424
|
+
}
|
|
1425
|
+
root ??= await fs.realpath(this.config.cwd);
|
|
1426
|
+
const resolved = await fs.realpath(path.resolve(root, attachment.path));
|
|
1427
|
+
const rel = path.relative(root, resolved);
|
|
1428
|
+
const escapes = rel === ".." || rel.startsWith(`..${path.sep}`);
|
|
1429
|
+
if (rel === "" || escapes || path.isAbsolute(rel)) {
|
|
1430
|
+
throw new Error(`Image attachment is outside the workspace: ${attachment.path}`);
|
|
1431
|
+
}
|
|
1432
|
+
const mimeType = mimeByExt[path.extname(resolved).toLowerCase()];
|
|
1433
|
+
if (!mimeType) {
|
|
1434
|
+
throw new Error(`Unsupported image type for attachment: ${attachment.path}`);
|
|
1435
|
+
}
|
|
1436
|
+
const { size } = await fs.stat(resolved);
|
|
1437
|
+
if (size > OMP_MAX_IMAGE_BYTES) {
|
|
1438
|
+
throw new Error(`Image attachment too large (${size} bytes > 5 MB): ${attachment.path}`);
|
|
1439
|
+
}
|
|
1440
|
+
images.push({
|
|
1441
|
+
type: "image",
|
|
1442
|
+
data: (await fs.readFile(resolved)).toString("base64"),
|
|
1443
|
+
mimeType
|
|
1444
|
+
});
|
|
1445
|
+
}
|
|
1446
|
+
const message = preamble.length ? `${preamble.join("\n")}
|
|
1447
|
+
|
|
1448
|
+
${input.text}` : input.text;
|
|
1449
|
+
return { message, ...images.length ? { images } : {} };
|
|
1450
|
+
}
|
|
1451
|
+
/**
|
|
1452
|
+
* Send one `prompt` frame and resolve when the turn completes (`agent_end`).
|
|
1453
|
+
* Rejects if the child dies first.
|
|
1454
|
+
*/
|
|
1455
|
+
async runPrompt(payload) {
|
|
698
1456
|
await this.start();
|
|
1457
|
+
await this.syncReconfigure();
|
|
699
1458
|
const id = this.nextId();
|
|
700
1459
|
const turnPromise = new Promise((resolve, reject) => {
|
|
701
1460
|
this.turnResolve = resolve;
|
|
702
1461
|
this.turnReject = reject;
|
|
703
1462
|
});
|
|
1463
|
+
this.beginUsageTurn();
|
|
704
1464
|
try {
|
|
705
|
-
this.send({ id, type: "prompt",
|
|
1465
|
+
this.send({ id, type: "prompt", ...payload });
|
|
706
1466
|
} catch (err) {
|
|
707
1467
|
this.turnResolve = null;
|
|
708
1468
|
this.turnReject = null;
|
|
@@ -721,6 +1481,7 @@ var OmpDriver = class extends AgentDriver {
|
|
|
721
1481
|
if (!this.proc) return;
|
|
722
1482
|
const id = this.nextId();
|
|
723
1483
|
this.send({ id, type: "abort" });
|
|
1484
|
+
this.cancelPendingQuestion();
|
|
724
1485
|
}
|
|
725
1486
|
/** `true` when the omp child process is alive and has not been killed. */
|
|
726
1487
|
get isRunning() {
|
|
@@ -733,14 +1494,18 @@ var OmpDriver = class extends AgentDriver {
|
|
|
733
1494
|
* `OmpDriver` to start a fresh session.
|
|
734
1495
|
*/
|
|
735
1496
|
kill() {
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
1497
|
+
const proc = this.proc;
|
|
1498
|
+
if (!proc) return;
|
|
1499
|
+
this.rejectTurn(new Error("omp process killed"));
|
|
1500
|
+
proc.kill("SIGTERM");
|
|
1501
|
+
this.cleanup();
|
|
740
1502
|
}
|
|
741
1503
|
async resetSession() {
|
|
742
1504
|
this.kill();
|
|
743
1505
|
this.config = { ...this.config, resumeSessionId: void 0 };
|
|
1506
|
+
this._lastTokens = null;
|
|
1507
|
+
this._lastContextTokens = null;
|
|
1508
|
+
this._contextWindow = null;
|
|
744
1509
|
await this.start();
|
|
745
1510
|
}
|
|
746
1511
|
classifyProcessError(err) {
|
|
@@ -803,6 +1568,14 @@ var OmpDriver = class extends AgentDriver {
|
|
|
803
1568
|
this.ready = false;
|
|
804
1569
|
this.startPromise = null;
|
|
805
1570
|
this.stderrBuffer = [];
|
|
1571
|
+
this.unsubscribeToolsChanged?.();
|
|
1572
|
+
this.unsubscribeToolsChanged = null;
|
|
1573
|
+
this.hostToolCapabilities = /* @__PURE__ */ new Map();
|
|
1574
|
+
for (const id of [...this.hostToolCalls.keys()]) this.abortHostToolCall(id);
|
|
1575
|
+
for (const fail of [...this.pendingRequests.values()]) fail(new Error("omp process ended"));
|
|
1576
|
+
this.pendingRequests.clear();
|
|
1577
|
+
this.quietRequestIds.clear();
|
|
1578
|
+
this.pendingQuestion = null;
|
|
806
1579
|
}
|
|
807
1580
|
};
|
|
808
1581
|
var ompDriverTarget = {
|
|
@@ -819,6 +1592,6 @@ var ompDriverTarget = {
|
|
|
819
1592
|
}).listModels()
|
|
820
1593
|
};
|
|
821
1594
|
|
|
822
|
-
export { OMP_BUILTIN_TOOLS, OMP_DEFAULT_TOOLS, OmpDriver, buildOmpChildEnv, buildOmpToolArgs, ompDriverTarget };
|
|
1595
|
+
export { OMP_BUILTIN_TOOLS, OMP_DEFAULT_TOOLS, OMP_THINKING_LEVELS, OmpDriver, buildOmpChildEnv, buildOmpHostTools, buildOmpToolArgs, ompDriverTarget, ompThinkingLevel, splitOmpModel };
|
|
823
1596
|
//# sourceMappingURL=omp.js.map
|
|
824
1597
|
//# sourceMappingURL=omp.js.map
|