@bastani/atomic 0.9.51-alpha.1 → 0.9.52-alpha.1
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 +12 -0
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/web-access/CHANGELOG.md +6 -0
- package/dist/builtin/web-access/index.bundle.mjs +49 -10
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +11 -0
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +67 -7
- package/dist/builtin/workflows/src/extension/local-worker-entry.mjs +47 -3
- package/dist/builtin/workflows/src/index.js +47 -3
- package/dist/builtin/workflows/src/local-worker-entry.mjs +47 -3
- package/docs/web-access.md +41 -3
- package/docs/workflows/operations.md +1 -1
- package/npm-shrinkwrap.json +32 -32
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.9.51] - 2026-10-29
|
|
6
|
+
|
|
7
|
+
Windows sessions resume as printed, and stay open.
|
|
8
|
+
|
|
9
|
+
- **Resume commands that work in cmd.exe:** the command Atomic prints on exit quotes paths for Windows shells, so pasting it into `cmd.exe` or PowerShell resumes the session instead of failing to open the session store ([#4095](https://github.com/bastani-inc/atomic/issues/4095))
|
|
10
|
+
- **No exits from stray signals:** a Ctrl+C signal that another process sends to the console no longer clears the editor or ends an idle session; it can still interrupt work that is running ([#4096](https://github.com/bastani-inc/atomic/issues/4096))
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- The resume command printed on exit quotes paths for the shell on Windows: none for a plain path, double quotes for one with spaces, never single quotes, which `cmd.exe` passed through as part of the path ([#4095](https://github.com/bastani-inc/atomic/issues/4095))
|
|
15
|
+
- A SIGINT signal that didn't come from the keyboard, such as a console control event another process in the same Windows console raises, no longer clears the editor or counts toward the double-Ctrl+C exit while the terminal is in raw mode; it still interrupts a running response, bash command, compaction or retry ([#4096](https://github.com/bastani-inc/atomic/issues/4096))
|
|
16
|
+
|
|
5
17
|
## [0.9.51-alpha.1] - 2026-10-29
|
|
6
18
|
|
|
7
19
|
Windows sessions resume as printed, and stay open.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/intercom",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.52-alpha.1",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Atomic extension providing a private coordination channel between parent and child agent sessions. Fork of: https://github.com/nicobailon/pi-intercom",
|
|
6
6
|
"contributors": [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/subagents",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.52-alpha.1",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Atomic extension for delegating tasks to subagents with parallel execution. Fork of: https://github.com/nicobailon/pi-subagents",
|
|
6
6
|
"contributors": [
|
|
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.9.52-alpha.1] - 2026-10-29
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- `web_search` no longer ends with `Search curation cancelled (stale).` when the search curator is enabled but cannot open (for example on a machine with no desktop browser), or when the session has no human to answer it, such as a subagent or workflow stage. It returns the raw results, with a note that points to `/curator off` when the curator failed to open. When no search provider is reachable, the error now names the `EXA_API_KEY`, `PERPLEXITY_API_KEY`, and `GEMINI_API_KEY` environment variables, the `exaApiKey`, `perplexityApiKey`, and `geminiApiKey` fields in `~/.atomic/web-search.json`, and `/curator` ([#4087](https://github.com/bastani-inc/atomic/issues/4087)).
|
|
12
|
+
|
|
7
13
|
## [0.9.40] - 2026-10-20
|
|
8
14
|
|
|
9
15
|
### Changed
|
|
@@ -96673,6 +96673,14 @@ function normalizeSearchProvider(value) {
|
|
|
96673
96673
|
const normalized = typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
96674
96674
|
return normalized === "auto" || normalized === "perplexity" || normalized === "gemini" || normalized === "exa" ? normalized : "auto";
|
|
96675
96675
|
}
|
|
96676
|
+
function providerSetupHint() {
|
|
96677
|
+
return `To configure a search provider, either:
|
|
96678
|
+
` + ` 1. Set EXA_API_KEY, PERPLEXITY_API_KEY, or GEMINI_API_KEY in the environment
|
|
96679
|
+
` + ` 2. Add exaApiKey, perplexityApiKey, or geminiApiKey to ~/${CONFIG_DIR_NAME4}/web-search.json
|
|
96680
|
+
` + " 3. Sign into gemini.google.com in a supported Chromium-based browser and allow browser cookies " + `(allowBrowserCookies: true in ~/${CONFIG_DIR_NAME4}/web-search.json)
|
|
96681
|
+
` + `Without a key, Exa's keyless fallback needs network access to mcp.exa.ai.
|
|
96682
|
+
` + "/curator only toggles the interactive review browser; it does not add a search provider. " + "Run /curator off if the curator keeps failing to open.";
|
|
96683
|
+
}
|
|
96676
96684
|
function errorMessage3(err) {
|
|
96677
96685
|
return err instanceof Error ? err.message : String(err);
|
|
96678
96686
|
}
|
|
@@ -96776,13 +96784,11 @@ async function search(query, options = {}) {
|
|
|
96776
96784
|
if (fallbackErrors.length > 0) {
|
|
96777
96785
|
throw new Error(`Auto provider search failed:
|
|
96778
96786
|
- ${fallbackErrors.join(`
|
|
96779
|
-
- `)}
|
|
96787
|
+
- `)}
|
|
96788
|
+
${providerSetupHint()}`);
|
|
96780
96789
|
}
|
|
96781
|
-
throw new Error(`No search provider available.
|
|
96782
|
-
|
|
96783
|
-
` + ` 2. Set EXA_API_KEY (or exaApiKey) in ~/${CONFIG_DIR_NAME4}/web-search.json
|
|
96784
|
-
` + ` 3. Set GEMINI_API_KEY in ~/${CONFIG_DIR_NAME4}/web-search.json
|
|
96785
|
-
` + " 4. Sign into gemini.google.com in a supported Chromium-based browser");
|
|
96790
|
+
throw new Error(`No search provider available.
|
|
96791
|
+
${providerSetupHint()}`);
|
|
96786
96792
|
}
|
|
96787
96793
|
async function searchWithGeminiApi(query, options = {}) {
|
|
96788
96794
|
const apiKey = getApiKey2();
|
|
@@ -97739,8 +97745,11 @@ async function openCuratorBrowser(deps, pc, searchesComplete = true) {
|
|
|
97739
97745
|
const message = err instanceof Error ? err.message : String(err);
|
|
97740
97746
|
if (!reportOwnedWebDiagnostic())
|
|
97741
97747
|
console.error(`Failed to open curator UI: ${message}`);
|
|
97742
|
-
if (deps.state.pendingCurate === pc
|
|
97743
|
-
|
|
97748
|
+
if (deps.state.pendingCurate === pc)
|
|
97749
|
+
pc.curatorUnavailable(message);
|
|
97750
|
+
if (handle && deps.state.activeCurator === handle) {
|
|
97751
|
+
deps.state.activeCurator = null;
|
|
97752
|
+
handle.close();
|
|
97744
97753
|
}
|
|
97745
97754
|
}
|
|
97746
97755
|
}
|
|
@@ -98150,7 +98159,8 @@ function registerWebSearchTool(pi, deps) {
|
|
|
98150
98159
|
const rawQueryList = Array.isArray(params.queries) ? params.queries : params.query !== undefined ? [params.query] : [];
|
|
98151
98160
|
const queryList = normalizeQueryList(rawQueryList);
|
|
98152
98161
|
const configWorkflow = loadConfigForExtensionInit().workflow;
|
|
98153
|
-
const
|
|
98162
|
+
const canCurate = ctx?.hasUI !== false && ctx?.hasHumanInput !== false;
|
|
98163
|
+
const workflow = resolveWorkflow(configWorkflow, canCurate);
|
|
98154
98164
|
const shouldCurate = workflow !== "none";
|
|
98155
98165
|
if (queryList.length === 0) {
|
|
98156
98166
|
return {
|
|
@@ -98183,6 +98193,7 @@ function registerWebSearchTool(pi, deps) {
|
|
|
98183
98193
|
const searchAbort = new AbortController;
|
|
98184
98194
|
const searchSignal = signal ? AbortSignal.any([signal, searchAbort.signal]) : searchAbort.signal;
|
|
98185
98195
|
let cancelled = false;
|
|
98196
|
+
let curatorFailure;
|
|
98186
98197
|
const bootstrap = await loadCuratorBootstrap(params.provider);
|
|
98187
98198
|
const availableProviders = bootstrap.availableProviders;
|
|
98188
98199
|
const defaultProvider = bootstrap.defaultProvider;
|
|
@@ -98216,7 +98227,8 @@ function registerWebSearchTool(pi, deps) {
|
|
|
98216
98227
|
searchAbort.abort();
|
|
98217
98228
|
},
|
|
98218
98229
|
finish: () => {},
|
|
98219
|
-
cancel: () => {}
|
|
98230
|
+
cancel: () => {},
|
|
98231
|
+
curatorUnavailable: () => {}
|
|
98220
98232
|
};
|
|
98221
98233
|
const onAbort = () => deps.closeCurator();
|
|
98222
98234
|
const finish = (value) => {
|
|
@@ -98233,8 +98245,16 @@ function registerWebSearchTool(pi, deps) {
|
|
|
98233
98245
|
return;
|
|
98234
98246
|
finish(buildCurationCancelledReturn(reason));
|
|
98235
98247
|
};
|
|
98248
|
+
const curatorUnavailable = (reason) => {
|
|
98249
|
+
if (cancelled)
|
|
98250
|
+
return;
|
|
98251
|
+
curatorFailure = reason;
|
|
98252
|
+
if (deps.state.pendingCurate === pc)
|
|
98253
|
+
deps.state.pendingCurate = null;
|
|
98254
|
+
};
|
|
98236
98255
|
pc.finish = finish;
|
|
98237
98256
|
pc.cancel = cancel;
|
|
98257
|
+
pc.curatorUnavailable = curatorUnavailable;
|
|
98238
98258
|
deps.state.pendingCurate = pc;
|
|
98239
98259
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
98240
98260
|
pc.browserPromise = deps.openCuratorBrowser(pc, false);
|
|
@@ -98282,6 +98302,25 @@ function registerWebSearchTool(pi, deps) {
|
|
|
98282
98302
|
return promise;
|
|
98283
98303
|
}
|
|
98284
98304
|
await pc.browserPromise;
|
|
98305
|
+
if (curatorFailure !== undefined) {
|
|
98306
|
+
const all = collectAllResultsAndUrls(searchResults);
|
|
98307
|
+
const raw = await deps.buildSearchReturn({
|
|
98308
|
+
queryList: all.results.map((r) => r.query),
|
|
98309
|
+
results: all.results,
|
|
98310
|
+
urls: all.urls,
|
|
98311
|
+
includeContent,
|
|
98312
|
+
inlineContent: allInlineContent.length > 0 ? allInlineContent : undefined
|
|
98313
|
+
});
|
|
98314
|
+
const note = `Note: the search curator could not open (${curatorFailure}), so these are raw results. ` + "Run /curator off to stop opening it.";
|
|
98315
|
+
const [first, ...rest] = raw.content;
|
|
98316
|
+
finish({
|
|
98317
|
+
content: [{ type: "text", text: `${note}
|
|
98318
|
+
|
|
98319
|
+
${first?.text ?? ""}`.trim() }, ...rest],
|
|
98320
|
+
details: { ...raw.details, curatorUnavailable: curatorFailure }
|
|
98321
|
+
});
|
|
98322
|
+
return promise;
|
|
98323
|
+
}
|
|
98285
98324
|
if (deps.state.activeCurator) {
|
|
98286
98325
|
deps.state.activeCurator.searchesDone();
|
|
98287
98326
|
pc.onUpdate?.({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/web-access",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.52-alpha.1",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Atomic extension for web search, URL fetching, GitHub repo cloning, PDF/video extraction. Fork of: https://github.com/nicobailon/pi-web-access",
|
|
6
6
|
"contributors": [
|
|
@@ -6,6 +6,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.9.52-alpha.1] - 2026-10-29
|
|
10
|
+
|
|
11
|
+
Stage chats show their own status lines, and web search keeps its results.
|
|
12
|
+
|
|
13
|
+
- **A stage chat's own status lines:** an attached stage chat's footer shows the extension statuses its stage's session writes, such as a tokens-per-second counter, and no longer the main session's ([#4094](https://github.com/bastani-inc/atomic/issues/4094))
|
|
14
|
+
- **Web search results that arrive:** `web_search` returns its results when the search curator can't open or nobody can answer it, instead of `Search curation cancelled (stale).`, and says which keys or settings to configure when no search provider works ([#4087](https://github.com/bastani-inc/atomic/issues/4087))
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- An attached stage chat's footer now shows the extension status lines (such as a tokens-per-second counter) written by that stage's own session, and no longer shows the main session's. Status writes from a stage's extensions used to be dropped, while the chat footer displayed the main chat's statuses: a sleeping stage showed a live counter driven by the main agent, and a streaming stage showed a stale one. The main chat footer keeps showing only the main session's statuses ([#4094](https://github.com/bastani-inc/atomic/issues/4094))
|
|
19
|
+
|
|
9
20
|
## [0.9.46] - 2026-10-27
|
|
10
21
|
|
|
11
22
|
### Added
|
|
@@ -5041,9 +5041,49 @@ class StageUiBroker {
|
|
|
5041
5041
|
resolvedPromptIds = new Map;
|
|
5042
5042
|
resolvedListeners = new Set;
|
|
5043
5043
|
registeredListeners = new Set;
|
|
5044
|
+
statuses = new Map;
|
|
5045
|
+
statusListeners = new Set;
|
|
5044
5046
|
constructor(store = currentWorkflowStore()) {
|
|
5045
5047
|
this.store = store;
|
|
5046
5048
|
}
|
|
5049
|
+
setStageStatus(runId, stageId, statusKey, text) {
|
|
5050
|
+
const stageKey = key(runId, stageId);
|
|
5051
|
+
const current = this.statuses.get(stageKey);
|
|
5052
|
+
if (text === undefined) {
|
|
5053
|
+
if (!current?.delete(statusKey))
|
|
5054
|
+
return;
|
|
5055
|
+
if (current.size === 0)
|
|
5056
|
+
this.statuses.delete(stageKey);
|
|
5057
|
+
} else {
|
|
5058
|
+
if (current?.get(statusKey) === text)
|
|
5059
|
+
return;
|
|
5060
|
+
if (current)
|
|
5061
|
+
current.set(statusKey, text);
|
|
5062
|
+
else
|
|
5063
|
+
this.statuses.set(stageKey, new Map([[statusKey, text]]));
|
|
5064
|
+
}
|
|
5065
|
+
this.notifyStatusesChanged();
|
|
5066
|
+
}
|
|
5067
|
+
getStageStatuses(runId, stageId) {
|
|
5068
|
+
return this.statuses.get(key(runId, stageId)) ?? EMPTY_STATUSES;
|
|
5069
|
+
}
|
|
5070
|
+
clearStageStatuses(runId, stageId) {
|
|
5071
|
+
if (this.statuses.delete(key(runId, stageId)))
|
|
5072
|
+
this.notifyStatusesChanged();
|
|
5073
|
+
}
|
|
5074
|
+
onStageStatusesChanged(listener) {
|
|
5075
|
+
this.statusListeners.add(listener);
|
|
5076
|
+
return () => {
|
|
5077
|
+
this.statusListeners.delete(listener);
|
|
5078
|
+
};
|
|
5079
|
+
}
|
|
5080
|
+
notifyStatusesChanged() {
|
|
5081
|
+
for (const listener of this.statusListeners) {
|
|
5082
|
+
try {
|
|
5083
|
+
listener();
|
|
5084
|
+
} catch {}
|
|
5085
|
+
}
|
|
5086
|
+
}
|
|
5047
5087
|
provideStagePrompt(runId, stageId, adapter) {
|
|
5048
5088
|
const hostKey = key(runId, stageId);
|
|
5049
5089
|
this.adapters.set(hostKey, adapter);
|
|
@@ -5270,10 +5310,11 @@ function adoptStageUiBroker(scope, preserveCurrentWhenTargetExists = false, stor
|
|
|
5270
5310
|
function currentStageUiBroker() {
|
|
5271
5311
|
return singleton3.current();
|
|
5272
5312
|
}
|
|
5273
|
-
var SESSION_KEY3 = "workflows:stage-ui:v1", singleton3, stageUiBroker;
|
|
5313
|
+
var EMPTY_STATUSES, SESSION_KEY3 = "workflows:stage-ui:v1", singleton3, stageUiBroker;
|
|
5274
5314
|
var init_stage_ui_broker = __esm(() => {
|
|
5275
5315
|
init_session_scoped_singleton();
|
|
5276
5316
|
init_store_factory();
|
|
5317
|
+
EMPTY_STATUSES = new Map;
|
|
5277
5318
|
singleton3 = createSessionScopedSingleton(SESSION_KEY3, () => new StageUiBroker);
|
|
5278
5319
|
stageUiBroker = singleton3.facade;
|
|
5279
5320
|
});
|
|
@@ -12360,9 +12401,9 @@ function makeStageExtensionUiContext(ui, meta, broker, inheritedBindingRevision,
|
|
|
12360
12401
|
onTerminalInput: ui.onTerminalInput ?? (() => () => {
|
|
12361
12402
|
return;
|
|
12362
12403
|
}),
|
|
12363
|
-
setStatus: ui.setStatus ?? (() => {
|
|
12404
|
+
setStatus: meta === undefined ? ui.setStatus ?? (() => {
|
|
12364
12405
|
return;
|
|
12365
|
-
}),
|
|
12406
|
+
}) : (statusKey, text) => broker.setStageStatus(meta.runId, meta.stageId, statusKey, text),
|
|
12366
12407
|
setWorkingMessage: ui.setWorkingMessage ?? (() => {
|
|
12367
12408
|
return;
|
|
12368
12409
|
}),
|
|
@@ -12497,6 +12538,8 @@ function buildRuntimeAdapters(builtWith, options = {}) {
|
|
|
12497
12538
|
if (meta?.isFallbackAttempt && inheritedOptions.model && inheritedOptions.isFallbackModelAllowed?.(inheritedOptions.model, inheritedOptions.thinkingLevel) === false)
|
|
12498
12539
|
throw new Error("Workflow stage fallback model unavailable under inherited policy.");
|
|
12499
12540
|
const sessionOptions = withWorkflowStageSessionOptions(inheritedOptions, meta, pi);
|
|
12541
|
+
if (meta !== undefined)
|
|
12542
|
+
broker.clearStageStatuses(meta.runId, meta.stageId);
|
|
12500
12543
|
const stageUi = shouldBindStageUiContext(pi, meta) ? makeStageExtensionUiContext(pi.ui ?? {}, meta, broker, inheritedOptions.extensionBindings?.humanInput === undefined ? 0 : 1, stageOptions.extensionBindings?.humanInput !== undefined) : undefined;
|
|
12501
12544
|
if (stageUi)
|
|
12502
12545
|
sessionOptions.extensionBindings = {
|
|
@@ -79686,6 +79729,7 @@ function createWorkflowStageFactory(input) {
|
|
|
79686
79729
|
stageSnapshot.artifacts = artifacts;
|
|
79687
79730
|
input.activeStore.recordStageEnd(input.runId, stageSnapshot);
|
|
79688
79731
|
input.stageUiBroker.cancelStagePrompt(input.runId, stageId, new Error(`atomic-workflows: stage ${stageId} completed with pending custom UI`));
|
|
79732
|
+
input.stageUiBroker.clearStageStatuses(input.runId, stageId);
|
|
79689
79733
|
if (input.opts.onStageEnd) {
|
|
79690
79734
|
await runCallback3({ kind: "workflow.stage_adapter", name: `onStageEnd:${name}`, runId: input.runId, stageId }, () => input.opts.onStageEnd(input.runId, stageSnapshot));
|
|
79691
79735
|
}
|
|
@@ -90223,7 +90267,10 @@ function editorRuleColor(ctx, disabled, agentSession, state) {
|
|
|
90223
90267
|
|
|
90224
90268
|
// dist/builtin/workflows/src/tui/stage-chat-view-state.ts
|
|
90225
90269
|
init_stage_ui_broker();
|
|
90226
|
-
import {
|
|
90270
|
+
import {
|
|
90271
|
+
ChatSessionHost,
|
|
90272
|
+
classifyChatCommand
|
|
90273
|
+
} from "@bastani/atomic";
|
|
90227
90274
|
import { Editor } from "@earendil-works/pi-tui";
|
|
90228
90275
|
|
|
90229
90276
|
// dist/builtin/workflows/src/tui/prompt-card-input.ts
|
|
@@ -91064,8 +91111,8 @@ function initializeStageChatView(ctx, opts) {
|
|
|
91064
91111
|
ctx.piEditorFactory = opts.piEditorFactory;
|
|
91065
91112
|
ctx.getToolsExpanded = opts.getToolsExpanded;
|
|
91066
91113
|
ctx.setToolsExpanded = opts.setToolsExpanded;
|
|
91067
|
-
ctx.footerData = opts.footerData;
|
|
91068
91114
|
ctx.stageUiBroker = opts.stageUiBroker ?? stageUiBroker;
|
|
91115
|
+
ctx.footerData = opts.footerData && stageFooterData(opts.footerData, ctx.stageUiBroker, opts.runId, opts.stageId);
|
|
91069
91116
|
ctx.canSubmitPrompt = opts.canSubmitPrompt;
|
|
91070
91117
|
ctx.mountedCustomUi = null;
|
|
91071
91118
|
ctx.mountingRequestId = null;
|
|
@@ -91113,7 +91160,12 @@ function initializeStageChatView(ctx, opts) {
|
|
|
91113
91160
|
if (initialChatIsTerminal)
|
|
91114
91161
|
ctx.chatHost.clearBusyForTerminalWorkflowStage();
|
|
91115
91162
|
ctx._unsubscribeStore = subscribeStoreInvalidation(ctx.store, () => handleStoreUpdate(ctx));
|
|
91116
|
-
|
|
91163
|
+
const unsubscribeBranch = ctx.footerData?.onBranchChange(() => ctx.requestRender?.());
|
|
91164
|
+
const unsubscribeStatuses = ctx.footerData ? ctx.stageUiBroker.onStageStatusesChanged(() => ctx.requestRender?.()) : undefined;
|
|
91165
|
+
ctx._unsubscribeFooterData = () => {
|
|
91166
|
+
unsubscribeBranch?.();
|
|
91167
|
+
unsubscribeStatuses?.();
|
|
91168
|
+
};
|
|
91117
91169
|
if (ctx.handle) {
|
|
91118
91170
|
ctx._unsubscribeDeliveryActivity = subscribeStageChatDeliveryActivity(ctx);
|
|
91119
91171
|
ctx._unsubscribeHandle = ctx.handle.subscribe((event) => applyStageChatLiveHandleEvent(ctx, event));
|
|
@@ -91163,6 +91215,14 @@ function installFocusHold(ctx) {
|
|
|
91163
91215
|
ctx.requestFocus?.();
|
|
91164
91216
|
}, 150);
|
|
91165
91217
|
}
|
|
91218
|
+
function stageFooterData(hostFooterData, broker, runId, stageId) {
|
|
91219
|
+
return {
|
|
91220
|
+
getGitBranch: (cwd) => hostFooterData.getGitBranch(cwd),
|
|
91221
|
+
getAvailableProviderCount: () => hostFooterData.getAvailableProviderCount(),
|
|
91222
|
+
onBranchChange: (callback, cwd) => hostFooterData.onBranchChange(callback, cwd),
|
|
91223
|
+
getExtensionStatuses: () => broker.getStageStatuses(runId, stageId)
|
|
91224
|
+
};
|
|
91225
|
+
}
|
|
91166
91226
|
function createChatHost(ctx, opts) {
|
|
91167
91227
|
return new ChatSessionHost({
|
|
91168
91228
|
taskRowsInChat: false,
|
|
@@ -91266,7 +91326,7 @@ function createChatHost(ctx, opts) {
|
|
|
91266
91326
|
editorFactory: opts.piEditorFactory,
|
|
91267
91327
|
editorTheme: editorThemeFromGraphTheme(ctx.theme),
|
|
91268
91328
|
getChatRenderSettings: () => stageChatRenderSettings(ctx, opts),
|
|
91269
|
-
footerData:
|
|
91329
|
+
footerData: ctx.footerData,
|
|
91270
91330
|
renderExtraEntry: (entry) => noticeRow(entry, ctx.theme)
|
|
91271
91331
|
});
|
|
91272
91332
|
}
|
|
@@ -9246,9 +9246,49 @@ class StageUiBroker {
|
|
|
9246
9246
|
resolvedPromptIds = new Map;
|
|
9247
9247
|
resolvedListeners = new Set;
|
|
9248
9248
|
registeredListeners = new Set;
|
|
9249
|
+
statuses = new Map;
|
|
9250
|
+
statusListeners = new Set;
|
|
9249
9251
|
constructor(store = currentWorkflowStore()) {
|
|
9250
9252
|
this.store = store;
|
|
9251
9253
|
}
|
|
9254
|
+
setStageStatus(runId, stageId, statusKey, text) {
|
|
9255
|
+
const stageKey = key(runId, stageId);
|
|
9256
|
+
const current = this.statuses.get(stageKey);
|
|
9257
|
+
if (text === undefined) {
|
|
9258
|
+
if (!current?.delete(statusKey))
|
|
9259
|
+
return;
|
|
9260
|
+
if (current.size === 0)
|
|
9261
|
+
this.statuses.delete(stageKey);
|
|
9262
|
+
} else {
|
|
9263
|
+
if (current?.get(statusKey) === text)
|
|
9264
|
+
return;
|
|
9265
|
+
if (current)
|
|
9266
|
+
current.set(statusKey, text);
|
|
9267
|
+
else
|
|
9268
|
+
this.statuses.set(stageKey, new Map([[statusKey, text]]));
|
|
9269
|
+
}
|
|
9270
|
+
this.notifyStatusesChanged();
|
|
9271
|
+
}
|
|
9272
|
+
getStageStatuses(runId, stageId) {
|
|
9273
|
+
return this.statuses.get(key(runId, stageId)) ?? EMPTY_STATUSES;
|
|
9274
|
+
}
|
|
9275
|
+
clearStageStatuses(runId, stageId) {
|
|
9276
|
+
if (this.statuses.delete(key(runId, stageId)))
|
|
9277
|
+
this.notifyStatusesChanged();
|
|
9278
|
+
}
|
|
9279
|
+
onStageStatusesChanged(listener) {
|
|
9280
|
+
this.statusListeners.add(listener);
|
|
9281
|
+
return () => {
|
|
9282
|
+
this.statusListeners.delete(listener);
|
|
9283
|
+
};
|
|
9284
|
+
}
|
|
9285
|
+
notifyStatusesChanged() {
|
|
9286
|
+
for (const listener of this.statusListeners) {
|
|
9287
|
+
try {
|
|
9288
|
+
listener();
|
|
9289
|
+
} catch {}
|
|
9290
|
+
}
|
|
9291
|
+
}
|
|
9252
9292
|
provideStagePrompt(runId, stageId, adapter) {
|
|
9253
9293
|
const hostKey = key(runId, stageId);
|
|
9254
9294
|
this.adapters.set(hostKey, adapter);
|
|
@@ -9442,10 +9482,11 @@ class StageUiBroker {
|
|
|
9442
9482
|
function currentStageUiBroker() {
|
|
9443
9483
|
return singleton2.current();
|
|
9444
9484
|
}
|
|
9445
|
-
var SESSION_KEY2 = "workflows:stage-ui:v1", singleton2, stageUiBroker;
|
|
9485
|
+
var EMPTY_STATUSES, SESSION_KEY2 = "workflows:stage-ui:v1", singleton2, stageUiBroker;
|
|
9446
9486
|
var init_stage_ui_broker = __esm(() => {
|
|
9447
9487
|
init_session_scoped_singleton();
|
|
9448
9488
|
init_store_factory();
|
|
9489
|
+
EMPTY_STATUSES = new Map;
|
|
9449
9490
|
singleton2 = createSessionScopedSingleton(SESSION_KEY2, () => new StageUiBroker);
|
|
9450
9491
|
stageUiBroker = singleton2.facade;
|
|
9451
9492
|
});
|
|
@@ -9851,9 +9892,9 @@ function makeStageExtensionUiContext(ui, meta, broker, inheritedBindingRevision,
|
|
|
9851
9892
|
onTerminalInput: ui.onTerminalInput ?? (() => () => {
|
|
9852
9893
|
return;
|
|
9853
9894
|
}),
|
|
9854
|
-
setStatus: ui.setStatus ?? (() => {
|
|
9895
|
+
setStatus: meta === undefined ? ui.setStatus ?? (() => {
|
|
9855
9896
|
return;
|
|
9856
|
-
}),
|
|
9897
|
+
}) : (statusKey, text) => broker.setStageStatus(meta.runId, meta.stageId, statusKey, text),
|
|
9857
9898
|
setWorkingMessage: ui.setWorkingMessage ?? (() => {
|
|
9858
9899
|
return;
|
|
9859
9900
|
}),
|
|
@@ -9988,6 +10029,8 @@ function buildRuntimeAdapters(builtWith, options = {}) {
|
|
|
9988
10029
|
if (meta?.isFallbackAttempt && inheritedOptions.model && inheritedOptions.isFallbackModelAllowed?.(inheritedOptions.model, inheritedOptions.thinkingLevel) === false)
|
|
9989
10030
|
throw new Error("Workflow stage fallback model unavailable under inherited policy.");
|
|
9990
10031
|
const sessionOptions = withWorkflowStageSessionOptions(inheritedOptions, meta, pi);
|
|
10032
|
+
if (meta !== undefined)
|
|
10033
|
+
broker.clearStageStatuses(meta.runId, meta.stageId);
|
|
9991
10034
|
const stageUi = shouldBindStageUiContext(pi, meta) ? makeStageExtensionUiContext(pi.ui ?? {}, meta, broker, inheritedOptions.extensionBindings?.humanInput === undefined ? 0 : 1, stageOptions.extensionBindings?.humanInput !== undefined) : undefined;
|
|
9992
10035
|
if (stageUi)
|
|
9993
10036
|
sessionOptions.extensionBindings = {
|
|
@@ -77524,6 +77567,7 @@ function createWorkflowStageFactory(input) {
|
|
|
77524
77567
|
stageSnapshot.artifacts = artifacts;
|
|
77525
77568
|
input.activeStore.recordStageEnd(input.runId, stageSnapshot);
|
|
77526
77569
|
input.stageUiBroker.cancelStagePrompt(input.runId, stageId, new Error(`atomic-workflows: stage ${stageId} completed with pending custom UI`));
|
|
77570
|
+
input.stageUiBroker.clearStageStatuses(input.runId, stageId);
|
|
77527
77571
|
if (input.opts.onStageEnd) {
|
|
77528
77572
|
await runCallback3({ kind: "workflow.stage_adapter", name: `onStageEnd:${name}`, runId: input.runId, stageId }, () => input.opts.onStageEnd(input.runId, stageSnapshot));
|
|
77529
77573
|
}
|
|
@@ -6556,9 +6556,49 @@ class StageUiBroker {
|
|
|
6556
6556
|
resolvedPromptIds = new Map;
|
|
6557
6557
|
resolvedListeners = new Set;
|
|
6558
6558
|
registeredListeners = new Set;
|
|
6559
|
+
statuses = new Map;
|
|
6560
|
+
statusListeners = new Set;
|
|
6559
6561
|
constructor(store = currentWorkflowStore()) {
|
|
6560
6562
|
this.store = store;
|
|
6561
6563
|
}
|
|
6564
|
+
setStageStatus(runId, stageId, statusKey, text) {
|
|
6565
|
+
const stageKey = key(runId, stageId);
|
|
6566
|
+
const current = this.statuses.get(stageKey);
|
|
6567
|
+
if (text === undefined) {
|
|
6568
|
+
if (!current?.delete(statusKey))
|
|
6569
|
+
return;
|
|
6570
|
+
if (current.size === 0)
|
|
6571
|
+
this.statuses.delete(stageKey);
|
|
6572
|
+
} else {
|
|
6573
|
+
if (current?.get(statusKey) === text)
|
|
6574
|
+
return;
|
|
6575
|
+
if (current)
|
|
6576
|
+
current.set(statusKey, text);
|
|
6577
|
+
else
|
|
6578
|
+
this.statuses.set(stageKey, new Map([[statusKey, text]]));
|
|
6579
|
+
}
|
|
6580
|
+
this.notifyStatusesChanged();
|
|
6581
|
+
}
|
|
6582
|
+
getStageStatuses(runId, stageId) {
|
|
6583
|
+
return this.statuses.get(key(runId, stageId)) ?? EMPTY_STATUSES;
|
|
6584
|
+
}
|
|
6585
|
+
clearStageStatuses(runId, stageId) {
|
|
6586
|
+
if (this.statuses.delete(key(runId, stageId)))
|
|
6587
|
+
this.notifyStatusesChanged();
|
|
6588
|
+
}
|
|
6589
|
+
onStageStatusesChanged(listener) {
|
|
6590
|
+
this.statusListeners.add(listener);
|
|
6591
|
+
return () => {
|
|
6592
|
+
this.statusListeners.delete(listener);
|
|
6593
|
+
};
|
|
6594
|
+
}
|
|
6595
|
+
notifyStatusesChanged() {
|
|
6596
|
+
for (const listener of this.statusListeners) {
|
|
6597
|
+
try {
|
|
6598
|
+
listener();
|
|
6599
|
+
} catch {}
|
|
6600
|
+
}
|
|
6601
|
+
}
|
|
6562
6602
|
provideStagePrompt(runId, stageId, adapter) {
|
|
6563
6603
|
const hostKey = key(runId, stageId);
|
|
6564
6604
|
this.adapters.set(hostKey, adapter);
|
|
@@ -6752,10 +6792,11 @@ class StageUiBroker {
|
|
|
6752
6792
|
function currentStageUiBroker() {
|
|
6753
6793
|
return singleton2.current();
|
|
6754
6794
|
}
|
|
6755
|
-
var SESSION_KEY2 = "workflows:stage-ui:v1", singleton2, stageUiBroker;
|
|
6795
|
+
var EMPTY_STATUSES, SESSION_KEY2 = "workflows:stage-ui:v1", singleton2, stageUiBroker;
|
|
6756
6796
|
var init_stage_ui_broker = __esm(() => {
|
|
6757
6797
|
init_session_scoped_singleton();
|
|
6758
6798
|
init_store_factory();
|
|
6799
|
+
EMPTY_STATUSES = new Map;
|
|
6759
6800
|
singleton2 = createSessionScopedSingleton(SESSION_KEY2, () => new StageUiBroker);
|
|
6760
6801
|
stageUiBroker = singleton2.facade;
|
|
6761
6802
|
});
|
|
@@ -7161,9 +7202,9 @@ function makeStageExtensionUiContext(ui, meta, broker, inheritedBindingRevision,
|
|
|
7161
7202
|
onTerminalInput: ui.onTerminalInput ?? (() => () => {
|
|
7162
7203
|
return;
|
|
7163
7204
|
}),
|
|
7164
|
-
setStatus: ui.setStatus ?? (() => {
|
|
7205
|
+
setStatus: meta === undefined ? ui.setStatus ?? (() => {
|
|
7165
7206
|
return;
|
|
7166
|
-
}),
|
|
7207
|
+
}) : (statusKey, text) => broker.setStageStatus(meta.runId, meta.stageId, statusKey, text),
|
|
7167
7208
|
setWorkingMessage: ui.setWorkingMessage ?? (() => {
|
|
7168
7209
|
return;
|
|
7169
7210
|
}),
|
|
@@ -7298,6 +7339,8 @@ function buildRuntimeAdapters(builtWith, options = {}) {
|
|
|
7298
7339
|
if (meta?.isFallbackAttempt && inheritedOptions.model && inheritedOptions.isFallbackModelAllowed?.(inheritedOptions.model, inheritedOptions.thinkingLevel) === false)
|
|
7299
7340
|
throw new Error("Workflow stage fallback model unavailable under inherited policy.");
|
|
7300
7341
|
const sessionOptions = withWorkflowStageSessionOptions(inheritedOptions, meta, pi);
|
|
7342
|
+
if (meta !== undefined)
|
|
7343
|
+
broker.clearStageStatuses(meta.runId, meta.stageId);
|
|
7301
7344
|
const stageUi = shouldBindStageUiContext(pi, meta) ? makeStageExtensionUiContext(pi.ui ?? {}, meta, broker, inheritedOptions.extensionBindings?.humanInput === undefined ? 0 : 1, stageOptions.extensionBindings?.humanInput !== undefined) : undefined;
|
|
7302
7345
|
if (stageUi)
|
|
7303
7346
|
sessionOptions.extensionBindings = {
|
|
@@ -77504,6 +77547,7 @@ function createWorkflowStageFactory(input) {
|
|
|
77504
77547
|
stageSnapshot.artifacts = artifacts;
|
|
77505
77548
|
input.activeStore.recordStageEnd(input.runId, stageSnapshot);
|
|
77506
77549
|
input.stageUiBroker.cancelStagePrompt(input.runId, stageId, new Error(`atomic-workflows: stage ${stageId} completed with pending custom UI`));
|
|
77550
|
+
input.stageUiBroker.clearStageStatuses(input.runId, stageId);
|
|
77507
77551
|
if (input.opts.onStageEnd) {
|
|
77508
77552
|
await runCallback3({ kind: "workflow.stage_adapter", name: `onStageEnd:${name}`, runId: input.runId, stageId }, () => input.opts.onStageEnd(input.runId, stageSnapshot));
|
|
77509
77553
|
}
|
|
@@ -9246,9 +9246,49 @@ class StageUiBroker {
|
|
|
9246
9246
|
resolvedPromptIds = new Map;
|
|
9247
9247
|
resolvedListeners = new Set;
|
|
9248
9248
|
registeredListeners = new Set;
|
|
9249
|
+
statuses = new Map;
|
|
9250
|
+
statusListeners = new Set;
|
|
9249
9251
|
constructor(store = currentWorkflowStore()) {
|
|
9250
9252
|
this.store = store;
|
|
9251
9253
|
}
|
|
9254
|
+
setStageStatus(runId, stageId, statusKey, text) {
|
|
9255
|
+
const stageKey = key(runId, stageId);
|
|
9256
|
+
const current = this.statuses.get(stageKey);
|
|
9257
|
+
if (text === undefined) {
|
|
9258
|
+
if (!current?.delete(statusKey))
|
|
9259
|
+
return;
|
|
9260
|
+
if (current.size === 0)
|
|
9261
|
+
this.statuses.delete(stageKey);
|
|
9262
|
+
} else {
|
|
9263
|
+
if (current?.get(statusKey) === text)
|
|
9264
|
+
return;
|
|
9265
|
+
if (current)
|
|
9266
|
+
current.set(statusKey, text);
|
|
9267
|
+
else
|
|
9268
|
+
this.statuses.set(stageKey, new Map([[statusKey, text]]));
|
|
9269
|
+
}
|
|
9270
|
+
this.notifyStatusesChanged();
|
|
9271
|
+
}
|
|
9272
|
+
getStageStatuses(runId, stageId) {
|
|
9273
|
+
return this.statuses.get(key(runId, stageId)) ?? EMPTY_STATUSES;
|
|
9274
|
+
}
|
|
9275
|
+
clearStageStatuses(runId, stageId) {
|
|
9276
|
+
if (this.statuses.delete(key(runId, stageId)))
|
|
9277
|
+
this.notifyStatusesChanged();
|
|
9278
|
+
}
|
|
9279
|
+
onStageStatusesChanged(listener) {
|
|
9280
|
+
this.statusListeners.add(listener);
|
|
9281
|
+
return () => {
|
|
9282
|
+
this.statusListeners.delete(listener);
|
|
9283
|
+
};
|
|
9284
|
+
}
|
|
9285
|
+
notifyStatusesChanged() {
|
|
9286
|
+
for (const listener of this.statusListeners) {
|
|
9287
|
+
try {
|
|
9288
|
+
listener();
|
|
9289
|
+
} catch {}
|
|
9290
|
+
}
|
|
9291
|
+
}
|
|
9252
9292
|
provideStagePrompt(runId, stageId, adapter) {
|
|
9253
9293
|
const hostKey = key(runId, stageId);
|
|
9254
9294
|
this.adapters.set(hostKey, adapter);
|
|
@@ -9442,10 +9482,11 @@ class StageUiBroker {
|
|
|
9442
9482
|
function currentStageUiBroker() {
|
|
9443
9483
|
return singleton2.current();
|
|
9444
9484
|
}
|
|
9445
|
-
var SESSION_KEY2 = "workflows:stage-ui:v1", singleton2, stageUiBroker;
|
|
9485
|
+
var EMPTY_STATUSES, SESSION_KEY2 = "workflows:stage-ui:v1", singleton2, stageUiBroker;
|
|
9446
9486
|
var init_stage_ui_broker = __esm(() => {
|
|
9447
9487
|
init_session_scoped_singleton();
|
|
9448
9488
|
init_store_factory();
|
|
9489
|
+
EMPTY_STATUSES = new Map;
|
|
9449
9490
|
singleton2 = createSessionScopedSingleton(SESSION_KEY2, () => new StageUiBroker);
|
|
9450
9491
|
stageUiBroker = singleton2.facade;
|
|
9451
9492
|
});
|
|
@@ -9851,9 +9892,9 @@ function makeStageExtensionUiContext(ui, meta, broker, inheritedBindingRevision,
|
|
|
9851
9892
|
onTerminalInput: ui.onTerminalInput ?? (() => () => {
|
|
9852
9893
|
return;
|
|
9853
9894
|
}),
|
|
9854
|
-
setStatus: ui.setStatus ?? (() => {
|
|
9895
|
+
setStatus: meta === undefined ? ui.setStatus ?? (() => {
|
|
9855
9896
|
return;
|
|
9856
|
-
}),
|
|
9897
|
+
}) : (statusKey, text) => broker.setStageStatus(meta.runId, meta.stageId, statusKey, text),
|
|
9857
9898
|
setWorkingMessage: ui.setWorkingMessage ?? (() => {
|
|
9858
9899
|
return;
|
|
9859
9900
|
}),
|
|
@@ -9988,6 +10029,8 @@ function buildRuntimeAdapters(builtWith, options = {}) {
|
|
|
9988
10029
|
if (meta?.isFallbackAttempt && inheritedOptions.model && inheritedOptions.isFallbackModelAllowed?.(inheritedOptions.model, inheritedOptions.thinkingLevel) === false)
|
|
9989
10030
|
throw new Error("Workflow stage fallback model unavailable under inherited policy.");
|
|
9990
10031
|
const sessionOptions = withWorkflowStageSessionOptions(inheritedOptions, meta, pi);
|
|
10032
|
+
if (meta !== undefined)
|
|
10033
|
+
broker.clearStageStatuses(meta.runId, meta.stageId);
|
|
9991
10034
|
const stageUi = shouldBindStageUiContext(pi, meta) ? makeStageExtensionUiContext(pi.ui ?? {}, meta, broker, inheritedOptions.extensionBindings?.humanInput === undefined ? 0 : 1, stageOptions.extensionBindings?.humanInput !== undefined) : undefined;
|
|
9992
10035
|
if (stageUi)
|
|
9993
10036
|
sessionOptions.extensionBindings = {
|
|
@@ -77524,6 +77567,7 @@ function createWorkflowStageFactory(input) {
|
|
|
77524
77567
|
stageSnapshot.artifacts = artifacts;
|
|
77525
77568
|
input.activeStore.recordStageEnd(input.runId, stageSnapshot);
|
|
77526
77569
|
input.stageUiBroker.cancelStagePrompt(input.runId, stageId, new Error(`atomic-workflows: stage ${stageId} completed with pending custom UI`));
|
|
77570
|
+
input.stageUiBroker.clearStageStatuses(input.runId, stageId);
|
|
77527
77571
|
if (input.opts.onStageEnd) {
|
|
77528
77572
|
await runCallback3({ kind: "workflow.stage_adapter", name: `onStageEnd:${name}`, runId: input.runId, stageId }, () => input.opts.onStageEnd(input.runId, stageSnapshot));
|
|
77529
77573
|
}
|
package/docs/web-access.md
CHANGED
|
@@ -1,8 +1,46 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Web access
|
|
2
|
+
|
|
3
|
+
Atomic bundles `web_search` for searching the web and `fetch_content` for reading pages. `web_search` works with no setup; the sections below cover how it picks a provider and how to configure one.
|
|
4
|
+
|
|
5
|
+
## Searching with `web_search`
|
|
6
|
+
|
|
7
|
+
Pass `query`, or `queries` for several angles at once. `provider` can be `auto` (the default), `exa`, `perplexity`, or `gemini`.
|
|
8
|
+
|
|
9
|
+
With `auto`, Atomic uses the first provider that works:
|
|
10
|
+
|
|
11
|
+
1. **Exa**: with a key it calls the Exa API; without one it uses Exa's free keyless MCP endpoint (`mcp.exa.ai`), so an unconfigured machine with network access still gets results.
|
|
12
|
+
2. **Perplexity**, with a key.
|
|
13
|
+
3. **Gemini API**, with a key.
|
|
14
|
+
4. **Gemini Web**, using your signed-in Chromium-based browser. Browser cookie access is off by default; enable it with `allowBrowserCookies: true` or `ATOMIC_ALLOW_BROWSER_COOKIES=1`.
|
|
15
|
+
|
|
16
|
+
Keys come from the environment or from `~/.atomic/web-search.json`:
|
|
17
|
+
|
|
18
|
+
| Provider | Environment variable | `web-search.json` field |
|
|
19
|
+
| --- | --- | --- |
|
|
20
|
+
| Exa | `EXA_API_KEY` | `exaApiKey` |
|
|
21
|
+
| Perplexity | `PERPLEXITY_API_KEY` | `perplexityApiKey` |
|
|
22
|
+
| Gemini API | `GEMINI_API_KEY` | `geminiApiKey` |
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
{
|
|
26
|
+
"exaApiKey": "your-key",
|
|
27
|
+
"provider": "auto"
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`provider` sets the default provider. When no provider can be reached, the error names these settings.
|
|
32
|
+
|
|
33
|
+
### The search curator
|
|
34
|
+
|
|
35
|
+
By default `web_search` returns raw results. `/curator on` (or `"workflow": "summary-review"` in `web-search.json`) opens a browser page where you review the results and approve a summary before the agent sees them; `/curator off` turns it back off. The curator changes how results are reviewed, not which provider is used.
|
|
36
|
+
|
|
37
|
+
It needs an interactive session with a person at a browser. Subagents, workflow stages, and non-interactive runs skip it and return raw results. If the page cannot open, for example on a machine with no desktop browser, `web_search` returns raw results with a note instead of failing; run `/curator off` to stop trying.
|
|
38
|
+
|
|
39
|
+
## Fetching with `fetch_content`
|
|
2
40
|
|
|
3
41
|
Atomic's bundled `fetch_content` tool reads webpages, PDFs, GitHub repositories, YouTube videos, and local video files.
|
|
4
42
|
|
|
5
|
-
|
|
43
|
+
### Arguments
|
|
6
44
|
|
|
7
45
|
Always pass the lowercase `urls` field as a nonempty array of strings, even for one URL:
|
|
8
46
|
|
|
@@ -38,7 +76,7 @@ Existing prompts or integrations using `{"url": "..."}` must change to `{"urls":
|
|
|
38
76
|
|
|
39
77
|
Atomic can normalize a scalar `urls` string into a one-item array. Always use the documented array form in prompts and integrations; the legacy `url` field is not normalized.
|
|
40
78
|
|
|
41
|
-
|
|
79
|
+
### Troubleshooting
|
|
42
80
|
|
|
43
81
|
If argument validation fails, check that:
|
|
44
82
|
|
|
@@ -211,7 +211,7 @@ Surface behavior:
|
|
|
211
211
|
- **Wheel and trackpad** - While the workflow graph is active, vertical wheel/trackpad gestures pan it up and down, and horizontal gestures pan wide graphs left and right when the terminal exposes horizontal wheel events. Focused graph and stage-chat overlays receive those gestures through the fullscreen application route, so scrolling stays inside the active workflow surface instead of falling through to terminal or main-chat scrollback.
|
|
212
212
|
- **Selection and copying** - Graph panning, stage scrolling, click-to-attach, and drag or multi-click selection work without a separate selection mode. Copy uses OSC 52; if the terminal blocks it, use its Shift/Option modifier-drag bypass. `ctrl+t` retains the host thinking toggle, not a workflow action.
|
|
213
213
|
- **Tool and node detail** - Attached stage chats match main chat's tool-detail expansion behavior while keeping expansion state local to the workflow UI context. Press Ctrl+O (the configurable `app.tools.expand` binding) to expand every visible workflow node and tool card, including single, parallel, and nested subagent progress, current tool activity, and artifact paths; press it again to collapse them. The toggle works for active, completed, and archived stage views, including at the supported 40-column terminal minimum. A mounted prompt, custom question, or other input-owning overlay keeps the key instead of changing it.
|
|
214
|
-
- **Footer context** - An attached live stage chat shows its own current folder and Git branch and
|
|
214
|
+
- **Footer context** - An attached live stage chat shows its own current folder and Git branch and shows the live extension status lines that the stage's own session sets, such as the MCP server indicator, never the main chat's. Branch changes trigger a repaint through the host's cached footer provider. The compact `/tasks` picker retains this context and the stage's model and reasoning level even while its foreground turn streams; detail, transcript, input, and confirmation pages remain fullscreen.
|
|
215
215
|
- **Working indicator** - Stage chat shows `∀` during accepted prompt startup and active work, including retained-session follow-ups. Retry, fallback, compaction, cancellation, and errors take precedence. `NO_COLOR` removes foreground colors; `ATOMIC_REDUCED_MOTION=1` makes the indicator static.
|
|
216
216
|
- **Subagent statusline** - If a subagent is running while the fullscreen workflow graph is open, the graph statusline mirrors its summary so the run remains visible; hide the graph with `h`, leave it with `ctrl+x`, or reconnect later to return to the full below-editor widget.
|
|
217
217
|
- **Run control** - Use `pause` and `resume` for resumable live work. Pause holds a stage's queued steering and follow-up items in place without dequeuing them or starting continuation; `resume` releases those items once in their existing per-queue order, but queue release alone does not start a model turn. `resume` on a non-paused run reopens the saved snapshot or overlay. Use `quit` to pause a live run gracefully while preserving it for `/workflow resume`. `/workflow pause` selects the active run by default, accepts a full run id or `--all`, and does not open a stage picker. `/workflow pause <run-id> <stage>` pauses only that stage, named by id, name or unique prefix as `/workflow attach` resolves it, and `/workflow resume <run-id> <stage>` resumes it. The workflow tool's `stageId` does the same and also targets tool nodes.
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/atomic",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.52-alpha.1",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bastani/atomic",
|
|
9
|
-
"version": "0.9.
|
|
9
|
+
"version": "0.9.52-alpha.1",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@bastani/atomic-natives": "0.9.
|
|
13
|
-
"@bastani/pi-ai": "0.9.
|
|
12
|
+
"@bastani/atomic-natives": "0.9.52-alpha.1",
|
|
13
|
+
"@bastani/pi-ai": "0.9.52-alpha.1",
|
|
14
14
|
"@earendil-works/pi-agent-core": "1.4.0",
|
|
15
15
|
"@earendil-works/pi-codemode": "1.4.0",
|
|
16
16
|
"@earendil-works/pi-tui": "1.4.0",
|
|
@@ -427,18 +427,18 @@
|
|
|
427
427
|
}
|
|
428
428
|
},
|
|
429
429
|
"node_modules/@bastani/atomic-natives": {
|
|
430
|
-
"version": "0.9.
|
|
431
|
-
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives/-/atomic-natives-0.9.
|
|
430
|
+
"version": "0.9.52-alpha.1",
|
|
431
|
+
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives/-/atomic-natives-0.9.52-alpha.1.tgz",
|
|
432
432
|
"license": "MIT",
|
|
433
433
|
"optionalDependencies": {
|
|
434
|
-
"@bastani/atomic-natives-darwin-arm64": "0.9.
|
|
435
|
-
"@bastani/atomic-natives-darwin-x64": "0.9.
|
|
436
|
-
"@bastani/atomic-natives-linux-arm64-gnu": "0.9.
|
|
437
|
-
"@bastani/atomic-natives-linux-arm64-musl": "0.9.
|
|
438
|
-
"@bastani/atomic-natives-linux-x64-gnu": "0.9.
|
|
439
|
-
"@bastani/atomic-natives-linux-x64-musl": "0.9.
|
|
440
|
-
"@bastani/atomic-natives-win32-arm64-msvc": "0.9.
|
|
441
|
-
"@bastani/atomic-natives-win32-x64-msvc": "0.9.
|
|
434
|
+
"@bastani/atomic-natives-darwin-arm64": "0.9.52-alpha.1",
|
|
435
|
+
"@bastani/atomic-natives-darwin-x64": "0.9.52-alpha.1",
|
|
436
|
+
"@bastani/atomic-natives-linux-arm64-gnu": "0.9.52-alpha.1",
|
|
437
|
+
"@bastani/atomic-natives-linux-arm64-musl": "0.9.52-alpha.1",
|
|
438
|
+
"@bastani/atomic-natives-linux-x64-gnu": "0.9.52-alpha.1",
|
|
439
|
+
"@bastani/atomic-natives-linux-x64-musl": "0.9.52-alpha.1",
|
|
440
|
+
"@bastani/atomic-natives-win32-arm64-msvc": "0.9.52-alpha.1",
|
|
441
|
+
"@bastani/atomic-natives-win32-x64-msvc": "0.9.52-alpha.1"
|
|
442
442
|
},
|
|
443
443
|
"engines": {
|
|
444
444
|
"bun": ">=1.4.2",
|
|
@@ -446,8 +446,8 @@
|
|
|
446
446
|
}
|
|
447
447
|
},
|
|
448
448
|
"node_modules/@bastani/atomic-natives-darwin-arm64": {
|
|
449
|
-
"version": "0.9.
|
|
450
|
-
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-darwin-arm64/-/atomic-natives-darwin-arm64-0.9.
|
|
449
|
+
"version": "0.9.52-alpha.1",
|
|
450
|
+
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-darwin-arm64/-/atomic-natives-darwin-arm64-0.9.52-alpha.1.tgz",
|
|
451
451
|
"license": "MIT",
|
|
452
452
|
"os": [
|
|
453
453
|
"darwin"
|
|
@@ -458,8 +458,8 @@
|
|
|
458
458
|
"optional": true
|
|
459
459
|
},
|
|
460
460
|
"node_modules/@bastani/atomic-natives-darwin-x64": {
|
|
461
|
-
"version": "0.9.
|
|
462
|
-
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-darwin-x64/-/atomic-natives-darwin-x64-0.9.
|
|
461
|
+
"version": "0.9.52-alpha.1",
|
|
462
|
+
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-darwin-x64/-/atomic-natives-darwin-x64-0.9.52-alpha.1.tgz",
|
|
463
463
|
"license": "MIT",
|
|
464
464
|
"os": [
|
|
465
465
|
"darwin"
|
|
@@ -470,8 +470,8 @@
|
|
|
470
470
|
"optional": true
|
|
471
471
|
},
|
|
472
472
|
"node_modules/@bastani/atomic-natives-linux-arm64-gnu": {
|
|
473
|
-
"version": "0.9.
|
|
474
|
-
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-arm64-gnu/-/atomic-natives-linux-arm64-gnu-0.9.
|
|
473
|
+
"version": "0.9.52-alpha.1",
|
|
474
|
+
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-arm64-gnu/-/atomic-natives-linux-arm64-gnu-0.9.52-alpha.1.tgz",
|
|
475
475
|
"license": "MIT",
|
|
476
476
|
"os": [
|
|
477
477
|
"linux"
|
|
@@ -485,8 +485,8 @@
|
|
|
485
485
|
"optional": true
|
|
486
486
|
},
|
|
487
487
|
"node_modules/@bastani/atomic-natives-linux-arm64-musl": {
|
|
488
|
-
"version": "0.9.
|
|
489
|
-
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-arm64-musl/-/atomic-natives-linux-arm64-musl-0.9.
|
|
488
|
+
"version": "0.9.52-alpha.1",
|
|
489
|
+
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-arm64-musl/-/atomic-natives-linux-arm64-musl-0.9.52-alpha.1.tgz",
|
|
490
490
|
"license": "MIT",
|
|
491
491
|
"os": [
|
|
492
492
|
"linux"
|
|
@@ -500,8 +500,8 @@
|
|
|
500
500
|
"optional": true
|
|
501
501
|
},
|
|
502
502
|
"node_modules/@bastani/atomic-natives-linux-x64-gnu": {
|
|
503
|
-
"version": "0.9.
|
|
504
|
-
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-x64-gnu/-/atomic-natives-linux-x64-gnu-0.9.
|
|
503
|
+
"version": "0.9.52-alpha.1",
|
|
504
|
+
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-x64-gnu/-/atomic-natives-linux-x64-gnu-0.9.52-alpha.1.tgz",
|
|
505
505
|
"license": "MIT",
|
|
506
506
|
"os": [
|
|
507
507
|
"linux"
|
|
@@ -515,8 +515,8 @@
|
|
|
515
515
|
"optional": true
|
|
516
516
|
},
|
|
517
517
|
"node_modules/@bastani/atomic-natives-linux-x64-musl": {
|
|
518
|
-
"version": "0.9.
|
|
519
|
-
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-x64-musl/-/atomic-natives-linux-x64-musl-0.9.
|
|
518
|
+
"version": "0.9.52-alpha.1",
|
|
519
|
+
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-x64-musl/-/atomic-natives-linux-x64-musl-0.9.52-alpha.1.tgz",
|
|
520
520
|
"license": "MIT",
|
|
521
521
|
"os": [
|
|
522
522
|
"linux"
|
|
@@ -530,8 +530,8 @@
|
|
|
530
530
|
"optional": true
|
|
531
531
|
},
|
|
532
532
|
"node_modules/@bastani/atomic-natives-win32-arm64-msvc": {
|
|
533
|
-
"version": "0.9.
|
|
534
|
-
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-win32-arm64-msvc/-/atomic-natives-win32-arm64-msvc-0.9.
|
|
533
|
+
"version": "0.9.52-alpha.1",
|
|
534
|
+
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-win32-arm64-msvc/-/atomic-natives-win32-arm64-msvc-0.9.52-alpha.1.tgz",
|
|
535
535
|
"license": "MIT",
|
|
536
536
|
"os": [
|
|
537
537
|
"win32"
|
|
@@ -542,8 +542,8 @@
|
|
|
542
542
|
"optional": true
|
|
543
543
|
},
|
|
544
544
|
"node_modules/@bastani/atomic-natives-win32-x64-msvc": {
|
|
545
|
-
"version": "0.9.
|
|
546
|
-
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-win32-x64-msvc/-/atomic-natives-win32-x64-msvc-0.9.
|
|
545
|
+
"version": "0.9.52-alpha.1",
|
|
546
|
+
"resolved": "https://registry.npmjs.org/@bastani/atomic-natives-win32-x64-msvc/-/atomic-natives-win32-x64-msvc-0.9.52-alpha.1.tgz",
|
|
547
547
|
"license": "MIT",
|
|
548
548
|
"os": [
|
|
549
549
|
"win32"
|
|
@@ -554,8 +554,8 @@
|
|
|
554
554
|
"optional": true
|
|
555
555
|
},
|
|
556
556
|
"node_modules/@bastani/pi-ai": {
|
|
557
|
-
"version": "0.9.
|
|
558
|
-
"resolved": "https://registry.npmjs.org/@bastani/pi-ai/-/pi-ai-0.9.
|
|
557
|
+
"version": "0.9.52-alpha.1",
|
|
558
|
+
"resolved": "https://registry.npmjs.org/@bastani/pi-ai/-/pi-ai-0.9.52-alpha.1.tgz",
|
|
559
559
|
"license": "MIT",
|
|
560
560
|
"dependencies": {
|
|
561
561
|
"@anthropic-ai/sdk": "0.129.0",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/atomic",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.52-alpha.1",
|
|
4
4
|
"description": "Atomic coding agent CLI with read, bash, edit, write tools and session management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"atomicConfig": {
|
|
@@ -89,8 +89,8 @@
|
|
|
89
89
|
"prepublishOnly": "bun run clean && bun run build && bun run shrinkwrap"
|
|
90
90
|
},
|
|
91
91
|
"dependencies": {
|
|
92
|
-
"@bastani/atomic-natives": "0.9.
|
|
93
|
-
"@bastani/pi-ai": "0.9.
|
|
92
|
+
"@bastani/atomic-natives": "0.9.52-alpha.1",
|
|
93
|
+
"@bastani/pi-ai": "0.9.52-alpha.1",
|
|
94
94
|
"@earendil-works/pi-agent-core": "1.4.0",
|
|
95
95
|
"@earendil-works/pi-codemode": "1.4.0",
|
|
96
96
|
"@earendil-works/pi-tui": "1.4.0",
|