@superatomai/sdk-node 0.0.68-dsp → 0.0.69-dsp
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/README.md +942 -942
- package/dist/index.d.mts +400 -5
- package/dist/index.d.ts +400 -5
- package/dist/index.js +809 -57
- package/dist/index.mjs +824 -78
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -804,6 +804,101 @@ var CodingAgentAbortRequestMessageSchema = z3.object({
|
|
|
804
804
|
type: z3.literal("CODING_AGENT_ABORT_REQ"),
|
|
805
805
|
payload: CodingAgentAbortRequestPayloadSchema
|
|
806
806
|
});
|
|
807
|
+
var DashBuilderRequestPayloadSchema = z3.object({
|
|
808
|
+
/** The conversation. One per dashboard program, and the abort key. */
|
|
809
|
+
dashboardId: z3.string(),
|
|
810
|
+
/** What the person said. */
|
|
811
|
+
text: z3.string(),
|
|
812
|
+
/**
|
|
813
|
+
* A panel the person pointed at before typing.
|
|
814
|
+
*
|
|
815
|
+
* Its `Panel` id, the same key a saved arrangement stores against. Optional
|
|
816
|
+
* because most turns are about the dashboard rather than one panel of it, and
|
|
817
|
+
* carried as a field rather than folded into `text` so the transcript shows
|
|
818
|
+
* what the person actually wrote.
|
|
819
|
+
*/
|
|
820
|
+
panelId: z3.string().optional(),
|
|
821
|
+
projectId: z3.string().optional(),
|
|
822
|
+
userId: z3.string().optional()
|
|
823
|
+
});
|
|
824
|
+
var DashBuilderRequestMessageSchema = z3.object({
|
|
825
|
+
id: z3.string(),
|
|
826
|
+
from: MessageParticipantSchema,
|
|
827
|
+
type: z3.literal("DASH_BUILDER_REQ"),
|
|
828
|
+
payload: DashBuilderRequestPayloadSchema
|
|
829
|
+
});
|
|
830
|
+
var DashBuilderUpdateSchema = z3.discriminatedUnion("type", [
|
|
831
|
+
z3.object({ type: z3.literal("state"), running: z3.boolean() }),
|
|
832
|
+
z3.object({ type: z3.literal("user"), text: z3.string(), at: z3.number() }),
|
|
833
|
+
/**
|
|
834
|
+
* The tail of an assistant message that is still being written.
|
|
835
|
+
*
|
|
836
|
+
* Append-only and never part of the transcript: the `assistant` update that
|
|
837
|
+
* follows carries the same prose in full, so a client shows the accumulated
|
|
838
|
+
* deltas while a turn runs and drops them the moment the real message lands.
|
|
839
|
+
* A turn here runs for minutes, and without this the pane sits empty for all
|
|
840
|
+
* of it.
|
|
841
|
+
*/
|
|
842
|
+
z3.object({ type: z3.literal("delta"), text: z3.string() }),
|
|
843
|
+
z3.object({ type: z3.literal("assistant"), text: z3.string(), at: z3.number() }),
|
|
844
|
+
z3.object({ type: z3.literal("tool"), text: z3.string(), at: z3.number() }),
|
|
845
|
+
z3.object({ type: z3.literal("error"), text: z3.string(), at: z3.number() })
|
|
846
|
+
]);
|
|
847
|
+
var DashBuilderStreamPayloadSchema = z3.object({
|
|
848
|
+
dashboardId: z3.string(),
|
|
849
|
+
/**
|
|
850
|
+
* Monotonic per turn, so re-delivery is harmless.
|
|
851
|
+
*
|
|
852
|
+
* Copied from dashboard-agent rather than assumed unnecessary: duplicate and
|
|
853
|
+
* out-of-order delivery were observed there on long-running requests and were
|
|
854
|
+
* never explained by anything in the send/receive path itself. A turn here
|
|
855
|
+
* runs for minutes, which is the same exposure.
|
|
856
|
+
*/
|
|
857
|
+
seq: z3.number(),
|
|
858
|
+
update: DashBuilderUpdateSchema
|
|
859
|
+
});
|
|
860
|
+
var DashBuilderStreamMessageSchema = z3.object({
|
|
861
|
+
id: z3.string().optional(),
|
|
862
|
+
from: MessageParticipantSchema,
|
|
863
|
+
type: z3.literal("DASH_BUILDER_STREAM"),
|
|
864
|
+
payload: DashBuilderStreamPayloadSchema
|
|
865
|
+
});
|
|
866
|
+
var DashBuilderAbortRequestPayloadSchema = z3.object({
|
|
867
|
+
dashboardId: z3.string()
|
|
868
|
+
});
|
|
869
|
+
var DashBuilderAbortRequestMessageSchema = z3.object({
|
|
870
|
+
id: z3.string().optional(),
|
|
871
|
+
from: MessageParticipantSchema,
|
|
872
|
+
type: z3.literal("DASH_BUILDER_ABORT_REQ"),
|
|
873
|
+
payload: DashBuilderAbortRequestPayloadSchema
|
|
874
|
+
});
|
|
875
|
+
var DashComponentPropSchema = z3.union([
|
|
876
|
+
z3.string(),
|
|
877
|
+
z3.object({
|
|
878
|
+
description: z3.string(),
|
|
879
|
+
importance: z3.enum(["required", "recommended", "optional"]).optional(),
|
|
880
|
+
default: z3.union([z3.string(), z3.number(), z3.boolean()]).optional(),
|
|
881
|
+
caution: z3.string().optional(),
|
|
882
|
+
group: z3.string().optional()
|
|
883
|
+
})
|
|
884
|
+
]);
|
|
885
|
+
var DashComponentSchema = z3.object({
|
|
886
|
+
name: z3.string(),
|
|
887
|
+
kind: z3.string(),
|
|
888
|
+
purpose: z3.string(),
|
|
889
|
+
props: z3.record(DashComponentPropSchema).optional(),
|
|
890
|
+
useWhen: z3.string().optional(),
|
|
891
|
+
notes: z3.string().optional()
|
|
892
|
+
});
|
|
893
|
+
var DashContractResponsePayloadSchema = z3.object({
|
|
894
|
+
components: z3.array(DashComponentSchema)
|
|
895
|
+
});
|
|
896
|
+
var DashContractResponseMessageSchema = z3.object({
|
|
897
|
+
id: z3.string(),
|
|
898
|
+
from: MessageParticipantSchema,
|
|
899
|
+
type: z3.literal("DASH_CONTRACT_RES"),
|
|
900
|
+
payload: DashContractResponsePayloadSchema
|
|
901
|
+
});
|
|
807
902
|
var ReportCompRequestPayloadSchema = z3.object({
|
|
808
903
|
prompt: z3.string(),
|
|
809
904
|
userId: z3.string().optional(),
|
|
@@ -3728,7 +3823,7 @@ var TaggedStreamBuffer = class extends StreamBuffer {
|
|
|
3728
3823
|
}
|
|
3729
3824
|
};
|
|
3730
3825
|
function streamDelay(ms = STREAM_DELAY_MS) {
|
|
3731
|
-
return new Promise((
|
|
3826
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
3732
3827
|
}
|
|
3733
3828
|
async function withProgressHeartbeat(operation, progressMessage, streamBuffer, intervalMs = PROGRESS_HEARTBEAT_INTERVAL_MS) {
|
|
3734
3829
|
if (!streamBuffer.hasCallback()) {
|
|
@@ -10909,7 +11004,7 @@ var Semaphore = class {
|
|
|
10909
11004
|
`Script execution at capacity (${this.max} running, ${this.waiters.length} queued). Try again shortly.`
|
|
10910
11005
|
);
|
|
10911
11006
|
}
|
|
10912
|
-
return new Promise((
|
|
11007
|
+
return new Promise((resolve3) => this.waiters.push(resolve3));
|
|
10913
11008
|
}
|
|
10914
11009
|
release() {
|
|
10915
11010
|
const next = this.waiters.shift();
|
|
@@ -11039,7 +11134,7 @@ FIX: pass every required parameter to execute_script, or give it a default in wr
|
|
|
11039
11134
|
}
|
|
11040
11135
|
}
|
|
11041
11136
|
function executeInSubprocess(scriptPath, params, paramSchema, externalTools, streamBuffer, timeoutMs, signal, mode, analysisData, analysisDatasets, entities, appliedPolicies) {
|
|
11042
|
-
return new Promise((
|
|
11137
|
+
return new Promise((resolve3) => {
|
|
11043
11138
|
const tsxBin = resolveTsxBinary();
|
|
11044
11139
|
const bootstrap = resolveBootstrapPath();
|
|
11045
11140
|
const contextToken = mintContextToken();
|
|
@@ -11095,7 +11190,7 @@ function executeInSubprocess(scriptPath, params, paramSchema, externalTools, str
|
|
|
11095
11190
|
clearTimeout(timer);
|
|
11096
11191
|
if (signal && onAbort) signal.removeEventListener("abort", onAbort);
|
|
11097
11192
|
cleanup();
|
|
11098
|
-
|
|
11193
|
+
resolve3(r);
|
|
11099
11194
|
};
|
|
11100
11195
|
const timer = setTimeout(() => {
|
|
11101
11196
|
finish({
|
|
@@ -18794,7 +18889,25 @@ RENDERING REQUIREMENT (overrides the default choice of component): ${carriedRequ
|
|
|
18794
18889
|
}
|
|
18795
18890
|
}
|
|
18796
18891
|
if (!usedLightweight) {
|
|
18797
|
-
logger.warn(`[AgentFlow] Component generation produced
|
|
18892
|
+
logger.warn(`[AgentFlow] Component generation produced no components \u2014 returning the analysis without a dashboard`);
|
|
18893
|
+
}
|
|
18894
|
+
}
|
|
18895
|
+
if (matchedComponents.length === 0) {
|
|
18896
|
+
const fallbackText = (agentResponse.text || "").replace(/<DashboardComponents>[\s\S]*?<\/DashboardComponents>/g, "").trim();
|
|
18897
|
+
if (fallbackText) {
|
|
18898
|
+
logger.info(`[AgentFlow] No components \u2014 wrapping the analysis in DynamicMarkdownBlock`);
|
|
18899
|
+
matchedComponents = [{
|
|
18900
|
+
id: "dynamic-markdown-block",
|
|
18901
|
+
name: "DynamicMarkdownBlock",
|
|
18902
|
+
type: "MarkdownBlock",
|
|
18903
|
+
description: "Text response rendered as markdown",
|
|
18904
|
+
props: { content: fallbackText }
|
|
18905
|
+
}];
|
|
18906
|
+
layoutTitle = "";
|
|
18907
|
+
layoutDescription = "";
|
|
18908
|
+
noDataAnswer = true;
|
|
18909
|
+
} else {
|
|
18910
|
+
logger.warn(`[AgentFlow] No components and no analysis text \u2014 returning an empty result`);
|
|
18798
18911
|
}
|
|
18799
18912
|
}
|
|
18800
18913
|
const queryMap = {};
|
|
@@ -19735,12 +19848,13 @@ async function handleUserPromptRequest(data, components, sendMessage, anthropicA
|
|
|
19735
19848
|
id: `comp_${Math.random().toString(36).substring(2, 8)}`
|
|
19736
19849
|
}));
|
|
19737
19850
|
}
|
|
19851
|
+
const { trace: _trace, ...dataWithoutTrace } = response.data ?? {};
|
|
19738
19852
|
sendDataResponse4(
|
|
19739
19853
|
response.id || data.id,
|
|
19740
19854
|
{
|
|
19741
19855
|
success: response.success,
|
|
19742
19856
|
errors: response.errors,
|
|
19743
|
-
data: response.data,
|
|
19857
|
+
data: response.data ? dataWithoutTrace : response.data,
|
|
19744
19858
|
uiBlockId: response.uiBlockId,
|
|
19745
19859
|
threadId: response.threadId
|
|
19746
19860
|
},
|
|
@@ -19937,6 +20051,26 @@ async function handleComponentListResponse(data, storeComponents, collections) {
|
|
|
19937
20051
|
}
|
|
19938
20052
|
}
|
|
19939
20053
|
|
|
20054
|
+
// src/handlers/dash-contract-response.ts
|
|
20055
|
+
async function handleDashContractResponse(data, storeDashContract, collections) {
|
|
20056
|
+
const parsed = DashContractResponseMessageSchema.safeParse(data);
|
|
20057
|
+
if (!parsed.success) {
|
|
20058
|
+
logger.error("[DashContract] Invalid message \u2014 ignoring");
|
|
20059
|
+
return;
|
|
20060
|
+
}
|
|
20061
|
+
const { components } = parsed.data.payload;
|
|
20062
|
+
storeDashContract(components);
|
|
20063
|
+
const register = collections?.["dashboard-builder"]?.["registerContract"];
|
|
20064
|
+
if (!register) return;
|
|
20065
|
+
try {
|
|
20066
|
+
await register({ components });
|
|
20067
|
+
} catch (error) {
|
|
20068
|
+
logger.warn(
|
|
20069
|
+
`[DashContract] Collection refused the contract: ${error instanceof Error ? error.message : String(error)}`
|
|
20070
|
+
);
|
|
20071
|
+
}
|
|
20072
|
+
}
|
|
20073
|
+
|
|
19940
20074
|
// src/handlers/workflow-list-response.ts
|
|
19941
20075
|
async function handleWorkflowListResponse(data, storeWorkflows) {
|
|
19942
20076
|
try {
|
|
@@ -24334,11 +24468,257 @@ ${marker}
|
|
|
24334
24468
|
};
|
|
24335
24469
|
}
|
|
24336
24470
|
|
|
24471
|
+
// src/codingAgent/drivers/pi.ts
|
|
24472
|
+
var dynamicImport2 = new Function("specifier", "return import(specifier)");
|
|
24473
|
+
var piModulePromise = null;
|
|
24474
|
+
function loadPi() {
|
|
24475
|
+
if (!piModulePromise) {
|
|
24476
|
+
piModulePromise = dynamicImport2("@earendil-works/pi-coding-agent").catch((err) => {
|
|
24477
|
+
piModulePromise = null;
|
|
24478
|
+
throw new Error(`@earendil-works/pi-coding-agent is not installed, so the pi harness is unavailable. (${err?.message ?? err})`);
|
|
24479
|
+
});
|
|
24480
|
+
}
|
|
24481
|
+
return piModulePromise;
|
|
24482
|
+
}
|
|
24483
|
+
var authAndRegistry = null;
|
|
24484
|
+
function getAuthAndRegistry() {
|
|
24485
|
+
if (!authAndRegistry) {
|
|
24486
|
+
authAndRegistry = loadPi().then(({ AuthStorage, ModelRegistry }) => {
|
|
24487
|
+
const authStorage = AuthStorage.create();
|
|
24488
|
+
return { authStorage, modelRegistry: ModelRegistry.create(authStorage) };
|
|
24489
|
+
});
|
|
24490
|
+
}
|
|
24491
|
+
return authAndRegistry;
|
|
24492
|
+
}
|
|
24493
|
+
var DEFAULT_PROVIDER = "openai-codex";
|
|
24494
|
+
var DEFAULT_MODEL_ID = process.env.PI_AGENT_MODEL || "gpt-5.5";
|
|
24495
|
+
var KNOWN_UNUSABLE_MODEL_IDS = /* @__PURE__ */ new Set(["gpt-5.3-codex-spark"]);
|
|
24496
|
+
async function resolveModel(modelRegistry, spec) {
|
|
24497
|
+
const [provider, modelId] = spec?.includes("/") ? [spec.slice(0, spec.indexOf("/")), spec.slice(spec.indexOf("/") + 1)] : [spec || DEFAULT_PROVIDER, void 0];
|
|
24498
|
+
const available = modelRegistry.getAvailable().filter((m) => m.provider === provider);
|
|
24499
|
+
const wanted = modelId ?? (spec ? void 0 : DEFAULT_MODEL_ID);
|
|
24500
|
+
const exact = wanted && (modelRegistry.find(provider, wanted) ?? available.find((m) => m.id === wanted));
|
|
24501
|
+
if (exact && modelRegistry.hasConfiguredAuth(exact)) return exact;
|
|
24502
|
+
const usable = available.filter((m) => !KNOWN_UNUSABLE_MODEL_IDS.has(m.id));
|
|
24503
|
+
if (usable.length) return usable[0];
|
|
24504
|
+
if (available.length) return available[0];
|
|
24505
|
+
throw new Error(
|
|
24506
|
+
`No model available from "${provider}". Authorise it in a terminal on this machine: run \`pi\`, then \`/login\`.`
|
|
24507
|
+
);
|
|
24508
|
+
}
|
|
24509
|
+
function emptyUsage2() {
|
|
24510
|
+
return { inputTokens: 0, outputTokens: 0, reasoningTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0, toolCalls: 0 };
|
|
24511
|
+
}
|
|
24512
|
+
var BUFFER_CAP2 = 64e3;
|
|
24513
|
+
var EVENT_CAP2 = 600;
|
|
24514
|
+
function normEvent2(ev) {
|
|
24515
|
+
switch (ev.type) {
|
|
24516
|
+
case "tool_execution_start":
|
|
24517
|
+
return { kind: "command", id: ev.toolCallId, command: ev.toolName ? `${ev.toolName} ${jsonPreview(ev.args)}` : void 0, status: "in_progress" };
|
|
24518
|
+
case "tool_execution_end":
|
|
24519
|
+
return { kind: "command", id: ev.toolCallId, status: ev.isError ? "failed" : "completed", done: true, output: textOf(ev.result) };
|
|
24520
|
+
default:
|
|
24521
|
+
return null;
|
|
24522
|
+
}
|
|
24523
|
+
}
|
|
24524
|
+
function jsonPreview(v) {
|
|
24525
|
+
if (v == null) return "";
|
|
24526
|
+
try {
|
|
24527
|
+
return JSON.stringify(v).slice(0, 160);
|
|
24528
|
+
} catch {
|
|
24529
|
+
return "";
|
|
24530
|
+
}
|
|
24531
|
+
}
|
|
24532
|
+
function textOf(content) {
|
|
24533
|
+
const blocks = content?.content ?? content;
|
|
24534
|
+
if (!Array.isArray(blocks)) return typeof content === "string" ? content : "";
|
|
24535
|
+
return blocks.filter((b) => b?.type === "text").map((b) => String(b.text ?? "")).join("").trim();
|
|
24536
|
+
}
|
|
24537
|
+
var TRANSCRIPT_CAP = 400;
|
|
24538
|
+
var sessionListeners = /* @__PURE__ */ new Set();
|
|
24539
|
+
function onPiSessionUpdate(listener) {
|
|
24540
|
+
sessionListeners.add(listener);
|
|
24541
|
+
return () => sessionListeners.delete(listener);
|
|
24542
|
+
}
|
|
24543
|
+
function getPiSessionState(sessionKey) {
|
|
24544
|
+
const live = liveSessions.get(sessionKey);
|
|
24545
|
+
return live ? { running: live.running, transcript: live.transcript } : void 0;
|
|
24546
|
+
}
|
|
24547
|
+
function publish(sessionKey, live, entry) {
|
|
24548
|
+
live.transcript.push(entry);
|
|
24549
|
+
if (live.transcript.length > TRANSCRIPT_CAP) live.transcript.splice(0, live.transcript.length - TRANSCRIPT_CAP);
|
|
24550
|
+
for (const listener of sessionListeners) listener(sessionKey, entry);
|
|
24551
|
+
}
|
|
24552
|
+
var liveSessions = /* @__PURE__ */ new Map();
|
|
24553
|
+
function newSessionId() {
|
|
24554
|
+
return `pi_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
|
|
24555
|
+
}
|
|
24556
|
+
var IDLE_TIMEOUT_MS = Number(process.env.PI_AGENT_IDLE_MS ?? 30 * 60 * 1e3);
|
|
24557
|
+
var sweeper = null;
|
|
24558
|
+
function startSweeper() {
|
|
24559
|
+
if (sweeper) return;
|
|
24560
|
+
sweeper = setInterval(() => {
|
|
24561
|
+
const cutoff = Date.now() - IDLE_TIMEOUT_MS;
|
|
24562
|
+
for (const [key, live] of liveSessions) {
|
|
24563
|
+
if (live.running || live.lastActive > cutoff) continue;
|
|
24564
|
+
live.session.dispose();
|
|
24565
|
+
liveSessions.delete(key);
|
|
24566
|
+
}
|
|
24567
|
+
if (liveSessions.size === 0 && sweeper) {
|
|
24568
|
+
clearInterval(sweeper);
|
|
24569
|
+
sweeper = null;
|
|
24570
|
+
}
|
|
24571
|
+
}, 6e4);
|
|
24572
|
+
sweeper.unref?.();
|
|
24573
|
+
}
|
|
24574
|
+
function createPiSession(opts) {
|
|
24575
|
+
let running = false;
|
|
24576
|
+
let sessionKey = opts.resumeId && liveSessions.has(opts.resumeId) ? opts.resumeId : void 0;
|
|
24577
|
+
async function ensureSession() {
|
|
24578
|
+
const existing = sessionKey ? liveSessions.get(sessionKey) : void 0;
|
|
24579
|
+
if (existing) return existing;
|
|
24580
|
+
const { createAgentSession, SessionManager } = await loadPi();
|
|
24581
|
+
const { authStorage, modelRegistry } = await getAuthAndRegistry();
|
|
24582
|
+
const model = await resolveModel(modelRegistry, opts.model);
|
|
24583
|
+
const { session } = await createAgentSession({
|
|
24584
|
+
cwd: opts.cwd,
|
|
24585
|
+
sessionManager: SessionManager.inMemory(),
|
|
24586
|
+
authStorage,
|
|
24587
|
+
modelRegistry,
|
|
24588
|
+
model,
|
|
24589
|
+
tools: opts.tools ?? ["bash"]
|
|
24590
|
+
});
|
|
24591
|
+
sessionKey = newSessionId();
|
|
24592
|
+
const live = { session, running: false, transcript: [], lastActive: Date.now(), eventLog: [], buf: "" };
|
|
24593
|
+
liveSessions.set(sessionKey, live);
|
|
24594
|
+
startSweeper();
|
|
24595
|
+
return live;
|
|
24596
|
+
}
|
|
24597
|
+
async function runTurn(prompt, handlers, signal) {
|
|
24598
|
+
const startedAt = Date.now();
|
|
24599
|
+
const usage = emptyUsage2();
|
|
24600
|
+
let status = "completed";
|
|
24601
|
+
let error;
|
|
24602
|
+
const finish = (live2) => ({
|
|
24603
|
+
status,
|
|
24604
|
+
answer: status === "error" || status === "aborted" ? "" : live2?.session.getLastAssistantText()?.trim() ?? "",
|
|
24605
|
+
ms: Date.now() - startedAt,
|
|
24606
|
+
usage,
|
|
24607
|
+
error,
|
|
24608
|
+
sessionId: sessionKey
|
|
24609
|
+
});
|
|
24610
|
+
if (signal?.aborted) {
|
|
24611
|
+
status = "aborted";
|
|
24612
|
+
return finish();
|
|
24613
|
+
}
|
|
24614
|
+
const live = await ensureSession();
|
|
24615
|
+
const key = sessionKey;
|
|
24616
|
+
live.running = true;
|
|
24617
|
+
live.lastActive = Date.now();
|
|
24618
|
+
publish(key, live, { at: Date.now(), kind: "user", text: prompt });
|
|
24619
|
+
const before = live.session.getSessionStats();
|
|
24620
|
+
const onAbort = () => {
|
|
24621
|
+
void live.session.abort();
|
|
24622
|
+
};
|
|
24623
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
24624
|
+
const emit = (chunk) => {
|
|
24625
|
+
live.buf = (live.buf + chunk).slice(-BUFFER_CAP2);
|
|
24626
|
+
handlers?.onOutput?.(chunk);
|
|
24627
|
+
};
|
|
24628
|
+
const unsubscribe = live.session.subscribe((ev) => {
|
|
24629
|
+
if (ev.type === "message_update" && ev.assistantMessageEvent?.type === "text_delta") {
|
|
24630
|
+
const delta = ev.assistantMessageEvent.delta;
|
|
24631
|
+
if (delta) {
|
|
24632
|
+
emit(delta);
|
|
24633
|
+
handlers?.onNarration?.(delta);
|
|
24634
|
+
}
|
|
24635
|
+
return;
|
|
24636
|
+
}
|
|
24637
|
+
if (ev.type === "tool_execution_start" || ev.type === "tool_execution_end") {
|
|
24638
|
+
if (ev.type === "tool_execution_end") usage.toolCalls++;
|
|
24639
|
+
const event = normEvent2(ev);
|
|
24640
|
+
if (!event) return;
|
|
24641
|
+
live.eventLog.push(event);
|
|
24642
|
+
if (live.eventLog.length > EVENT_CAP2) live.eventLog.shift();
|
|
24643
|
+
handlers?.onEvent?.(event);
|
|
24644
|
+
publish(key, live, { at: Date.now(), kind: "activity", event });
|
|
24645
|
+
if (ev.type === "tool_execution_start") emit(`
|
|
24646
|
+
\u2192 ${ev.toolName ?? "tool"} ${jsonPreview(ev.args)}
|
|
24647
|
+
`);
|
|
24648
|
+
return;
|
|
24649
|
+
}
|
|
24650
|
+
});
|
|
24651
|
+
try {
|
|
24652
|
+
if (signal?.aborted) {
|
|
24653
|
+
status = "aborted";
|
|
24654
|
+
return finish(live);
|
|
24655
|
+
}
|
|
24656
|
+
await live.session.prompt(prompt);
|
|
24657
|
+
const err = live.session.agent.state.errorMessage;
|
|
24658
|
+
if (err) {
|
|
24659
|
+
status = signal?.aborted ? "aborted" : "error";
|
|
24660
|
+
error = err;
|
|
24661
|
+
} else if (signal?.aborted) {
|
|
24662
|
+
status = "aborted";
|
|
24663
|
+
}
|
|
24664
|
+
} catch (err) {
|
|
24665
|
+
status = signal?.aborted ? "aborted" : "error";
|
|
24666
|
+
error = err?.message ?? String(err);
|
|
24667
|
+
} finally {
|
|
24668
|
+
unsubscribe();
|
|
24669
|
+
signal?.removeEventListener("abort", onAbort);
|
|
24670
|
+
live.running = false;
|
|
24671
|
+
live.lastActive = Date.now();
|
|
24672
|
+
}
|
|
24673
|
+
const after = live.session.getSessionStats();
|
|
24674
|
+
usage.inputTokens = Math.max(0, after.tokens.input - before.tokens.input);
|
|
24675
|
+
usage.outputTokens = Math.max(0, after.tokens.output - before.tokens.output);
|
|
24676
|
+
usage.cacheReadTokens = Math.max(0, after.tokens.cacheRead - before.tokens.cacheRead);
|
|
24677
|
+
usage.cacheWriteTokens = Math.max(0, after.tokens.cacheWrite - before.tokens.cacheWrite);
|
|
24678
|
+
usage.costUSD = Math.max(0, after.cost - before.cost);
|
|
24679
|
+
handlers?.onUsage?.({ ...usage });
|
|
24680
|
+
const result = finish(live);
|
|
24681
|
+
publish(key, live, result.status === "error" ? { at: Date.now(), kind: "error", text: result.error } : { at: Date.now(), kind: "assistant", text: result.answer });
|
|
24682
|
+
return result;
|
|
24683
|
+
}
|
|
24684
|
+
return {
|
|
24685
|
+
harness: "pi",
|
|
24686
|
+
kind: "events",
|
|
24687
|
+
async run(prompt, handlers, signal) {
|
|
24688
|
+
if (running) throw new Error("This pi session already has a turn in flight.");
|
|
24689
|
+
running = true;
|
|
24690
|
+
try {
|
|
24691
|
+
return await runTurn(prompt, handlers, signal);
|
|
24692
|
+
} finally {
|
|
24693
|
+
running = false;
|
|
24694
|
+
}
|
|
24695
|
+
},
|
|
24696
|
+
events: () => sessionKey ? liveSessions.get(sessionKey)?.eventLog ?? [] : [],
|
|
24697
|
+
buffer: () => sessionKey ? liveSessions.get(sessionKey)?.buf ?? "" : "",
|
|
24698
|
+
busy: () => running,
|
|
24699
|
+
sessionId: () => sessionKey,
|
|
24700
|
+
// Abandon for real — drop the live session so the next run starts fresh.
|
|
24701
|
+
reset: () => {
|
|
24702
|
+
if (sessionKey) {
|
|
24703
|
+
liveSessions.get(sessionKey)?.session.dispose();
|
|
24704
|
+
liveSessions.delete(sessionKey);
|
|
24705
|
+
}
|
|
24706
|
+
sessionKey = void 0;
|
|
24707
|
+
},
|
|
24708
|
+
// Local-only, same as the codex driver: the live session stays in the
|
|
24709
|
+
// module map so a later run with this sessionId can still resume it.
|
|
24710
|
+
dispose: () => {
|
|
24711
|
+
}
|
|
24712
|
+
};
|
|
24713
|
+
}
|
|
24714
|
+
|
|
24337
24715
|
// src/codingAgent/factory.ts
|
|
24338
24716
|
function createCodingAgentSession(harness, opts) {
|
|
24339
24717
|
switch (harness) {
|
|
24340
24718
|
case "codex":
|
|
24341
24719
|
return createCodexSession(opts);
|
|
24720
|
+
case "pi":
|
|
24721
|
+
return createPiSession(opts);
|
|
24342
24722
|
default:
|
|
24343
24723
|
throw new Error(`Unknown coding-agent harness: ${harness}`);
|
|
24344
24724
|
}
|
|
@@ -24740,9 +25120,6 @@ Fix ONLY that, and rewrite the same file at the same path. Do not re-run any que
|
|
|
24740
25120
|
}
|
|
24741
25121
|
}
|
|
24742
25122
|
|
|
24743
|
-
// src/codingAgent/tools/bridge-shims.ts
|
|
24744
|
-
import * as fs9 from "fs";
|
|
24745
|
-
|
|
24746
25123
|
// src/codingAgent/tools/read-only-sql.ts
|
|
24747
25124
|
var WRITE_KEYWORDS = [
|
|
24748
25125
|
"insert",
|
|
@@ -24797,9 +25174,45 @@ ${stripSqlNoise.toString()}
|
|
|
24797
25174
|
${assertReadOnlySql.toString().replace("export function", "function")}
|
|
24798
25175
|
`;
|
|
24799
25176
|
|
|
25177
|
+
// src/codingAgent/tools/shims.ts
|
|
25178
|
+
import * as fs9 from "fs";
|
|
25179
|
+
import * as path10 from "path";
|
|
25180
|
+
var resolve2 = (target, name) => typeof target === "string" ? path10.join(target, name) : target.pathTo(name);
|
|
25181
|
+
function writeShims(defs, target) {
|
|
25182
|
+
for (const def of defs) {
|
|
25183
|
+
const file = resolve2(target, def.name);
|
|
25184
|
+
fs9.writeFileSync(file, def.body, "utf-8");
|
|
25185
|
+
fs9.chmodSync(file, 493);
|
|
25186
|
+
}
|
|
25187
|
+
return defs.map((def) => ({ name: `./${def.name}`, summary: def.summary }));
|
|
25188
|
+
}
|
|
25189
|
+
function bridgePreamble(bridgeUrl, constants = {}) {
|
|
25190
|
+
const declared = Object.entries(constants).map(([name, value]) => `const ${name} = ${JSON.stringify(value)};`).join("\n");
|
|
25191
|
+
return `const BRIDGE = ${JSON.stringify(bridgeUrl)};
|
|
25192
|
+
${declared}
|
|
25193
|
+
|
|
25194
|
+
function post(path, payload) {
|
|
25195
|
+
return fetch(BRIDGE + path, {
|
|
25196
|
+
method: 'POST',
|
|
25197
|
+
headers: { 'content-type': 'application/json' },
|
|
25198
|
+
body: JSON.stringify(payload),
|
|
25199
|
+
}).then(async (r) => {
|
|
25200
|
+
const text = await r.text();
|
|
25201
|
+
if (!r.ok) { console.error('Request failed (' + r.status + '): ' + text.slice(0, 2000)); process.exit(1); }
|
|
25202
|
+
try { return JSON.parse(text); } catch { console.error(text); process.exit(1); }
|
|
25203
|
+
}).catch((e) => { console.error('Could not reach the backend: ' + (e && e.message)); process.exit(1); });
|
|
25204
|
+
}
|
|
25205
|
+
`;
|
|
25206
|
+
}
|
|
25207
|
+
|
|
24800
25208
|
// src/codingAgent/tools/bridge-shims.ts
|
|
24801
25209
|
function writeBridgeShims(ws, opts) {
|
|
24802
25210
|
const maxRows = opts.maxRows ?? 200;
|
|
25211
|
+
const directTools = opts.directTools ?? [];
|
|
25212
|
+
const entityTypes = opts.entityTypes ?? [];
|
|
25213
|
+
const conceptCatalog = opts.conceptCatalog ?? [];
|
|
25214
|
+
const hasKnowledgeBase = !!opts.knowledgeBase;
|
|
25215
|
+
const hasSearchableSource = opts.sources.some((s) => s.searchable);
|
|
24803
25216
|
const query = `#!/usr/bin/env node
|
|
24804
25217
|
// Read-only SQL against a data source. Generated per run \u2014 do not edit.
|
|
24805
25218
|
${READ_ONLY_SQL_SOURCE}
|
|
@@ -24809,7 +25222,7 @@ const CONTEXT_TOKEN = ${JSON.stringify(opts.contextToken ?? null)};
|
|
|
24809
25222
|
|
|
24810
25223
|
const [toolId, sql, limitArg] = process.argv.slice(2);
|
|
24811
25224
|
if (!toolId || !sql) {
|
|
24812
|
-
console.error('usage: ./query "<toolId>" "<sql>" [limit]\\nRun ./sources for the toolIds.');
|
|
25225
|
+
console.error('usage: node ./query "<toolId>" "<sql>" [limit]\\nRun: node ./sources \u2014 for the toolIds.');
|
|
24813
25226
|
process.exit(2);
|
|
24814
25227
|
}
|
|
24815
25228
|
try { assertReadOnlySql(sql); } catch (e) { console.error(String(e.message || e)); process.exit(2); }
|
|
@@ -24851,24 +25264,189 @@ fetch(BRIDGE + '/query', {
|
|
|
24851
25264
|
})
|
|
24852
25265
|
.catch((e) => { console.error('Could not reach the data bridge: ' + (e && e.message)); process.exit(1); });
|
|
24853
25266
|
`;
|
|
24854
|
-
const
|
|
24855
|
-
//
|
|
24856
|
-
|
|
25267
|
+
const runTool = `#!/usr/bin/env node
|
|
25268
|
+
// Invoke a pre-built business-logic tool. Generated per run \u2014 do not edit.
|
|
25269
|
+
const BRIDGE = ${JSON.stringify(opts.bridgeUrl)};
|
|
25270
|
+
|
|
25271
|
+
const [toolId, paramsArg] = process.argv.slice(2);
|
|
25272
|
+
if (!toolId) {
|
|
25273
|
+
console.error('usage: node ./run-tool "<toolId>" [\\'<json params>\\']\\nRun: node ./sources \u2014 for the toolIds and their params.');
|
|
25274
|
+
process.exit(2);
|
|
25275
|
+
}
|
|
25276
|
+
let params = {};
|
|
25277
|
+
if (paramsArg) {
|
|
25278
|
+
try { params = JSON.parse(paramsArg); }
|
|
25279
|
+
catch (e) { console.error('params must be JSON: ' + String(e.message || e)); process.exit(2); }
|
|
25280
|
+
}
|
|
25281
|
+
|
|
25282
|
+
fetch(BRIDGE + '/run-tool', {
|
|
25283
|
+
method: 'POST',
|
|
25284
|
+
headers: { 'content-type': 'application/json' },
|
|
25285
|
+
body: JSON.stringify({ toolId, params }),
|
|
25286
|
+
})
|
|
25287
|
+
.then(async (r) => {
|
|
25288
|
+
const text = await r.text();
|
|
25289
|
+
if (!r.ok) { console.error('Tool call failed (' + r.status + '): ' + text.slice(0, 2000)); process.exit(1); }
|
|
25290
|
+
let p; try { p = JSON.parse(text); } catch { console.log(text); return; }
|
|
25291
|
+
if (p && p.error) { console.error(String(p.error)); process.exit(1); }
|
|
25292
|
+
console.log(JSON.stringify(p.result ?? p, null, 2));
|
|
25293
|
+
})
|
|
25294
|
+
.catch((e) => { console.error('Could not reach the data bridge: ' + (e && e.message)); process.exit(1); });
|
|
24857
25295
|
`;
|
|
24858
|
-
|
|
24859
|
-
|
|
24860
|
-
|
|
24861
|
-
|
|
25296
|
+
const schemaSearch = `#!/usr/bin/env node
|
|
25297
|
+
// Keyword search over a large source's schema \u2014 call this BEFORE writing SQL
|
|
25298
|
+
// against a "searchable" source (see ./sources); its schema is too big to
|
|
25299
|
+
// have been shown to you in full, and guessing column names wastes a turn on
|
|
25300
|
+
// a failed query. Generated per run \u2014 do not edit.
|
|
25301
|
+
const BRIDGE = ${JSON.stringify(opts.bridgeUrl)};
|
|
25302
|
+
|
|
25303
|
+
const [toolId, ...keywords] = process.argv.slice(2);
|
|
25304
|
+
if (!toolId || !keywords.length) {
|
|
25305
|
+
console.error('usage: node ./schema-search "<toolId>" <keyword> [keyword...]\\nRun: node ./sources \u2014 for which toolIds are searchable.');
|
|
25306
|
+
process.exit(2);
|
|
25307
|
+
}
|
|
25308
|
+
|
|
25309
|
+
fetch(BRIDGE + '/schema-search', {
|
|
25310
|
+
method: 'POST',
|
|
25311
|
+
headers: { 'content-type': 'application/json' },
|
|
25312
|
+
body: JSON.stringify({ toolId, keywords }),
|
|
25313
|
+
})
|
|
25314
|
+
.then(async (r) => {
|
|
25315
|
+
const text = await r.text();
|
|
25316
|
+
if (!r.ok) { console.error('Schema search failed (' + r.status + '): ' + text.slice(0, 2000)); process.exit(1); }
|
|
25317
|
+
let p; try { p = JSON.parse(text); } catch { console.log(text); return; }
|
|
25318
|
+
if (p && p.error) { console.error(String(p.error)); process.exit(1); }
|
|
25319
|
+
console.log(p.result ?? p);
|
|
25320
|
+
})
|
|
25321
|
+
.catch((e) => { console.error('Could not reach the data bridge: ' + (e && e.message)); process.exit(1); });
|
|
25322
|
+
`;
|
|
25323
|
+
const resolveEntities = `#!/usr/bin/env node
|
|
25324
|
+
// Resolve named things (customers, projects, people, ...) to their real
|
|
25325
|
+
// database ids, and business concepts to table/column/join facts \u2014 one round
|
|
25326
|
+
// trip, either half optional. Call this BEFORE writing SQL about anything
|
|
25327
|
+
// named in the question; never guess or fuzzy-match a name yourself.
|
|
25328
|
+
// Generated per run \u2014 do not edit.
|
|
25329
|
+
const BRIDGE = ${JSON.stringify(opts.bridgeUrl)};
|
|
25330
|
+
|
|
25331
|
+
const [argJson] = process.argv.slice(2);
|
|
25332
|
+
if (!argJson) {
|
|
25333
|
+
console.error('usage: node ./resolve-entities \\'{"mentions":[{"text":"..."}],"entityTypes":["..."]}\\'\\nRun: node ./sources \u2014 for which entity types exist. Either field may be omitted.');
|
|
25334
|
+
process.exit(2);
|
|
25335
|
+
}
|
|
25336
|
+
let args;
|
|
25337
|
+
try { args = JSON.parse(argJson); }
|
|
25338
|
+
catch (e) { console.error('argument must be JSON: ' + String(e.message || e)); process.exit(2); }
|
|
25339
|
+
|
|
25340
|
+
fetch(BRIDGE + '/resolve-entities', {
|
|
25341
|
+
method: 'POST',
|
|
25342
|
+
headers: { 'content-type': 'application/json' },
|
|
25343
|
+
body: JSON.stringify({ mentions: args.mentions ?? [], entityTypes: args.entityTypes ?? [] }),
|
|
25344
|
+
})
|
|
25345
|
+
.then(async (r) => {
|
|
25346
|
+
const text = await r.text();
|
|
25347
|
+
if (!r.ok) { console.error('Entity resolution failed (' + r.status + '): ' + text.slice(0, 2000)); process.exit(1); }
|
|
25348
|
+
let p; try { p = JSON.parse(text); } catch { console.log(text); return; }
|
|
25349
|
+
if (p && p.error) { console.error(String(p.error)); process.exit(1); }
|
|
25350
|
+
console.log(JSON.stringify(p.result ?? p, null, 2));
|
|
25351
|
+
})
|
|
25352
|
+
.catch((e) => { console.error('Could not reach the data bridge: ' + (e && e.message)); process.exit(1); });
|
|
25353
|
+
`;
|
|
25354
|
+
const conceptCatalogShim = `#!/usr/bin/env node
|
|
25355
|
+
// Every verified concept \u2014 name, aliases, and what it is for. No bodies: the
|
|
25356
|
+
// whole vocabulary in one call, so you know what exists and which ones bear on
|
|
25357
|
+
// the question, instead of guessing a name into ./run-tool "concept". Read it,
|
|
25358
|
+
// then fetch the ones that apply. Call this once, early. There is no search
|
|
25359
|
+
// step and nothing to search: this is the complete list.
|
|
25360
|
+
// Generated per run \u2014 do not edit.
|
|
25361
|
+
const BRIDGE = ${JSON.stringify(opts.bridgeUrl)};
|
|
25362
|
+
|
|
25363
|
+
fetch(BRIDGE + '/concept-catalog', { method: 'POST', headers: { 'content-type': 'application/json' }, body: '{}' })
|
|
25364
|
+
.then(async (r) => {
|
|
25365
|
+
const text = await r.text();
|
|
25366
|
+
if (!r.ok) { console.error('Concept catalog fetch failed (' + r.status + '): ' + text.slice(0, 2000)); process.exit(1); }
|
|
25367
|
+
let p; try { p = JSON.parse(text); } catch { console.log(text); return; }
|
|
25368
|
+
if (p && p.error) { console.error(String(p.error)); process.exit(1); }
|
|
25369
|
+
console.log(JSON.stringify(p.result ?? p, null, 2));
|
|
25370
|
+
})
|
|
25371
|
+
.catch((e) => { console.error('Could not reach the data bridge: ' + (e && e.message)); process.exit(1); });
|
|
25372
|
+
`;
|
|
25373
|
+
const knowledgeBaseShim = `#!/usr/bin/env node
|
|
25374
|
+
// Free-form domain knowledge (gotchas, join paths, table/column meanings) \u2014
|
|
25375
|
+
// lower priority than the concept catalog: check ./concept-catalog / the
|
|
25376
|
+
// concept tool first for anything with a formal business-rule meaning, use
|
|
25377
|
+
// this directly for everything else.
|
|
25378
|
+
//
|
|
25379
|
+
// No args lists every node; get fetches the bodies. There is no search step
|
|
25380
|
+
// and nothing to search \u2014 the corpus is tens of nodes with one short title
|
|
25381
|
+
// each, same as ./concept-catalog. Generated per run \u2014 do not edit.
|
|
25382
|
+
const BRIDGE = ${JSON.stringify(opts.bridgeUrl)};
|
|
25383
|
+
|
|
25384
|
+
const [argJson] = process.argv.slice(2);
|
|
25385
|
+
let args;
|
|
25386
|
+
if (!argJson) {
|
|
25387
|
+
args = { method: 'catalog' };
|
|
25388
|
+
} else {
|
|
25389
|
+
try { args = JSON.parse(argJson); }
|
|
25390
|
+
catch (e) {
|
|
25391
|
+
console.error('argument must be JSON: ' + String(e.message || e));
|
|
25392
|
+
console.error('usage: node ./knowledge-base \u2192 every node: id, title, category, tags');
|
|
25393
|
+
console.error(' node ./knowledge-base \\'{"method":"get","ids":[12,31]}\\' \u2192 their content');
|
|
25394
|
+
process.exit(2);
|
|
24862
25395
|
}
|
|
24863
25396
|
}
|
|
24864
25397
|
|
|
25398
|
+
fetch(BRIDGE + '/knowledge-base', {
|
|
25399
|
+
method: 'POST',
|
|
25400
|
+
headers: { 'content-type': 'application/json' },
|
|
25401
|
+
body: JSON.stringify(args),
|
|
25402
|
+
})
|
|
25403
|
+
.then(async (r) => {
|
|
25404
|
+
const text = await r.text();
|
|
25405
|
+
if (!r.ok) { console.error('Knowledge base lookup failed (' + r.status + '): ' + text.slice(0, 2000)); process.exit(1); }
|
|
25406
|
+
let p; try { p = JSON.parse(text); } catch { console.log(text); return; }
|
|
25407
|
+
if (p && p.error) { console.error(String(p.error)); process.exit(1); }
|
|
25408
|
+
console.log(JSON.stringify(p.result ?? p, null, 2));
|
|
25409
|
+
})
|
|
25410
|
+
.catch((e) => { console.error('Could not reach the data bridge: ' + (e && e.message)); process.exit(1); });
|
|
25411
|
+
`;
|
|
25412
|
+
const sources = `#!/usr/bin/env node
|
|
25413
|
+
// The data sources you can query with ./query (and search with
|
|
25414
|
+
// ./schema-search when "searchable" is true), the pre-built tools you can
|
|
25415
|
+
// invoke with ./run-tool, and the entity types ./resolve-entities can
|
|
25416
|
+
// resolve names against. The concept catalog itself is NOT repeated here \u2014
|
|
25417
|
+
// run ./concept-catalog for that.
|
|
25418
|
+
console.log(${JSON.stringify(
|
|
25419
|
+
JSON.stringify({
|
|
25420
|
+
sources: opts.sources,
|
|
25421
|
+
directTools,
|
|
25422
|
+
entityTypes,
|
|
25423
|
+
...conceptCatalog.length ? { conceptCount: conceptCatalog.length } : {},
|
|
25424
|
+
...hasKnowledgeBase ? { knowledgeBase: true } : {}
|
|
25425
|
+
}, null, 2)
|
|
25426
|
+
)});
|
|
25427
|
+
`;
|
|
25428
|
+
const files = [
|
|
25429
|
+
["sources", sources, "(no arguments) \u2014 what you can query, which of those are searchable, the pre-built tools, and the entity types."],
|
|
25430
|
+
["query", query, '"<toolId>" "<sql>" [limit] \u2014 read-only SQL against one source. The only way to see real data. ./sources for the toolIds.']
|
|
25431
|
+
];
|
|
25432
|
+
if (opts.conceptCatalog) files.push(["concept-catalog", conceptCatalogShim, '(no arguments) \u2014 every verified concept: name, aliases, what it is for. No bodies. Read this before the schema; fetch bodies with ./run-tool "concept".']);
|
|
25433
|
+
if (hasKnowledgeBase) files.push(["knowledge-base", knowledgeBaseShim, `[ '{"method":"get","ids":[12,31]}' ] \u2014 free-form domain knowledge: gotchas, join paths, what a column really holds. No arguments lists every node; get fetches bodies. Ranks below concepts, above your own reading of the schema.`]);
|
|
25434
|
+
if (entityTypes.length) files.push(["resolve-entities", resolveEntities, `'{"mentions":[{"text":"<name>"}]}' \u2014 turn a name a person typed into the value stored in the data. Run it before filtering on any proper noun.`]);
|
|
25435
|
+
if (hasSearchableSource) files.push(["schema-search", schemaSearch, `"<toolId>" <keyword> [keyword...] \u2014 keyword search over a large source's schema. Required before writing SQL against a "searchable" source \u2014 its schema was never shown to you in full.`]);
|
|
25436
|
+
if (directTools.length) files.push(["run-tool", runTool, `"<toolId>" '<json params>' \u2014 invoke a pre-built business-logic tool, including "concept" get/run. ./sources lists each one's parameters.`]);
|
|
25437
|
+
return writeShims(
|
|
25438
|
+
files.map(([name, body, summary]) => ({ name, body, summary })),
|
|
25439
|
+
ws
|
|
25440
|
+
);
|
|
25441
|
+
}
|
|
25442
|
+
|
|
24865
25443
|
// src/codingAgent/triggers.ts
|
|
24866
25444
|
import * as fs10 from "fs";
|
|
24867
|
-
import * as
|
|
25445
|
+
import * as path11 from "path";
|
|
24868
25446
|
var EVENT_BURST_CAP = 200;
|
|
24869
25447
|
var capEvents = (events) => events.length > EVENT_BURST_CAP ? events.slice(-EVENT_BURST_CAP) : events;
|
|
24870
25448
|
function statePath2(agentId) {
|
|
24871
|
-
return
|
|
25449
|
+
return path11.join(getCodingAgentsConfig().runtimeDir, agentId, "_triggers.json");
|
|
24872
25450
|
}
|
|
24873
25451
|
function loadTriggerState(agentId) {
|
|
24874
25452
|
let raw;
|
|
@@ -24893,7 +25471,7 @@ function loadTriggerState(agentId) {
|
|
|
24893
25471
|
function saveTriggerState(agentId, state) {
|
|
24894
25472
|
try {
|
|
24895
25473
|
const p = statePath2(agentId);
|
|
24896
|
-
fs10.mkdirSync(
|
|
25474
|
+
fs10.mkdirSync(path11.dirname(p), { recursive: true });
|
|
24897
25475
|
fs10.writeFileSync(p, JSON.stringify(state, null, 2));
|
|
24898
25476
|
} catch (err) {
|
|
24899
25477
|
logger.warn(`[CodingAgent:${agentId}] failed to persist trigger state: ${err?.message ?? err}`);
|
|
@@ -25031,12 +25609,12 @@ function describeTriggers() {
|
|
|
25031
25609
|
|
|
25032
25610
|
// src/codingAgent/collection.ts
|
|
25033
25611
|
import * as fs11 from "fs";
|
|
25034
|
-
import * as
|
|
25612
|
+
import * as path12 from "path";
|
|
25035
25613
|
function isChattable(agent) {
|
|
25036
25614
|
return agent.mode !== "task";
|
|
25037
25615
|
}
|
|
25038
25616
|
function registerCodingAgentCollection(sdk, config2 = {}) {
|
|
25039
|
-
const runtimeDir = config2.runtimeDir || process.env.CODING_AGENT_RUNTIME_DIR ||
|
|
25617
|
+
const runtimeDir = config2.runtimeDir || process.env.CODING_AGENT_RUNTIME_DIR || path12.join(process.cwd(), ".coding-agent-runtime");
|
|
25040
25618
|
const defaultHarness = config2.harness || process.env.CODING_AGENT_HARNESS || "codex";
|
|
25041
25619
|
const sessions = /* @__PURE__ */ new Map();
|
|
25042
25620
|
const running = /* @__PURE__ */ new Set();
|
|
@@ -25096,7 +25674,7 @@ function registerCodingAgentCollection(sdk, config2 = {}) {
|
|
|
25096
25674
|
...record.status === "skipped" ? { error: `${def.title} is in the middle of a run \u2014 try again in a moment.` } : record.error ? { error: record.error } : {}
|
|
25097
25675
|
};
|
|
25098
25676
|
}
|
|
25099
|
-
const cwd =
|
|
25677
|
+
const cwd = path12.join(runtimeDir, "threads", threadId);
|
|
25100
25678
|
fs11.mkdirSync(cwd, { recursive: true });
|
|
25101
25679
|
let session = sessions.get(threadId);
|
|
25102
25680
|
if (!session) {
|
|
@@ -25262,6 +25840,134 @@ async function handleCodingAgentRequest(data, collections, sendMessage) {
|
|
|
25262
25840
|
}
|
|
25263
25841
|
}
|
|
25264
25842
|
|
|
25843
|
+
// src/dashBuilder/handler.ts
|
|
25844
|
+
var inFlightAborts4 = /* @__PURE__ */ new Map();
|
|
25845
|
+
var recentlyAborted4 = /* @__PURE__ */ new Map();
|
|
25846
|
+
var ABORT_TOMBSTONE_TTL_MS4 = 3e4;
|
|
25847
|
+
function setAbortTombstone4(dashboardId) {
|
|
25848
|
+
const now = Date.now();
|
|
25849
|
+
recentlyAborted4.set(dashboardId, now);
|
|
25850
|
+
for (const [key, ts] of recentlyAborted4) {
|
|
25851
|
+
if (now - ts > ABORT_TOMBSTONE_TTL_MS4) recentlyAborted4.delete(key);
|
|
25852
|
+
}
|
|
25853
|
+
}
|
|
25854
|
+
function consumeAbortTombstone4(dashboardId) {
|
|
25855
|
+
const ts = recentlyAborted4.get(dashboardId);
|
|
25856
|
+
if (ts === void 0) return false;
|
|
25857
|
+
recentlyAborted4.delete(dashboardId);
|
|
25858
|
+
return Date.now() - ts <= ABORT_TOMBSTONE_TTL_MS4;
|
|
25859
|
+
}
|
|
25860
|
+
function handleDashBuilderAbort(data, sendMessage) {
|
|
25861
|
+
const parsed = DashBuilderAbortRequestMessageSchema.safeParse(data);
|
|
25862
|
+
if (!parsed.success) {
|
|
25863
|
+
logger.warn("[DashBuilderAbort] Invalid message \u2014 ignoring");
|
|
25864
|
+
return;
|
|
25865
|
+
}
|
|
25866
|
+
const { payload, from } = parsed.data;
|
|
25867
|
+
const { dashboardId } = payload;
|
|
25868
|
+
const controller = inFlightAborts4.get(dashboardId);
|
|
25869
|
+
if (controller) {
|
|
25870
|
+
controller.abort();
|
|
25871
|
+
inFlightAborts4.delete(dashboardId);
|
|
25872
|
+
logger.info(`[DashBuilderAbort] Aborted in-flight turn for ${dashboardId}`);
|
|
25873
|
+
} else {
|
|
25874
|
+
setAbortTombstone4(dashboardId);
|
|
25875
|
+
logger.info(`[DashBuilderAbort] No in-flight turn for ${dashboardId} \u2014 tombstoned`);
|
|
25876
|
+
}
|
|
25877
|
+
try {
|
|
25878
|
+
sendMessage({
|
|
25879
|
+
id: `dash_builder_aborted_${dashboardId}`,
|
|
25880
|
+
type: "DASH_BUILDER_ABORTED",
|
|
25881
|
+
from: { type: "data-agent" },
|
|
25882
|
+
to: { type: "runtime", id: from.id },
|
|
25883
|
+
payload: { dashboardId }
|
|
25884
|
+
});
|
|
25885
|
+
} catch (err) {
|
|
25886
|
+
logger.warn(
|
|
25887
|
+
`[DashBuilderAbort] Failed to send abort ack: ${err instanceof Error ? err.message : String(err)}`
|
|
25888
|
+
);
|
|
25889
|
+
}
|
|
25890
|
+
}
|
|
25891
|
+
async function handleDashBuilderRequest(data, collections, sendMessage) {
|
|
25892
|
+
return runWithMessageIdentity(data, () => handleDashBuilderRequestInner(data, collections, sendMessage));
|
|
25893
|
+
}
|
|
25894
|
+
async function handleDashBuilderRequestInner(data, collections, sendMessage) {
|
|
25895
|
+
const parsed = DashBuilderRequestMessageSchema.safeParse(data);
|
|
25896
|
+
if (!parsed.success) {
|
|
25897
|
+
logger.error("[DashBuilderReq] Invalid message:", JSON.stringify(parsed.error.errors));
|
|
25898
|
+
return;
|
|
25899
|
+
}
|
|
25900
|
+
const { id, payload, from } = parsed.data;
|
|
25901
|
+
const { dashboardId, text, panelId, projectId, userId } = payload;
|
|
25902
|
+
const wsId = from.id;
|
|
25903
|
+
const respond = (res) => {
|
|
25904
|
+
sendMessage({
|
|
25905
|
+
id,
|
|
25906
|
+
type: "DASH_BUILDER_RES",
|
|
25907
|
+
from: { type: "data-agent" },
|
|
25908
|
+
to: { type: "runtime", id: wsId },
|
|
25909
|
+
payload: res
|
|
25910
|
+
});
|
|
25911
|
+
};
|
|
25912
|
+
if (!collections?.["dashboard-builder-agent"]?.["prompt"]) {
|
|
25913
|
+
respond({
|
|
25914
|
+
started: false,
|
|
25915
|
+
error: "The dashboard builder is not available in this environment (collection 'dashboard-builder-agent' not registered)."
|
|
25916
|
+
});
|
|
25917
|
+
return;
|
|
25918
|
+
}
|
|
25919
|
+
const abortController = new AbortController();
|
|
25920
|
+
if (consumeAbortTombstone4(dashboardId)) {
|
|
25921
|
+
abortController.abort();
|
|
25922
|
+
logger.info(`[DashBuilderReq] ${dashboardId} was pre-aborted \u2014 starting cancelled`);
|
|
25923
|
+
}
|
|
25924
|
+
inFlightAborts4.set(dashboardId, abortController);
|
|
25925
|
+
let seq = 0;
|
|
25926
|
+
const stream = (update) => {
|
|
25927
|
+
try {
|
|
25928
|
+
sendMessage({
|
|
25929
|
+
/**
|
|
25930
|
+
* Keyed by this request's id, not by dashboardId.
|
|
25931
|
+
*
|
|
25932
|
+
* dashboardId repeats across every turn in a conversation, so a
|
|
25933
|
+
* listener that failed to clean up would keep matching future turns
|
|
25934
|
+
* forever and interleave their output. A per-request id means a
|
|
25935
|
+
* stale listener simply never matches anything again.
|
|
25936
|
+
*/
|
|
25937
|
+
id: `dash_builder_stream_${id}`,
|
|
25938
|
+
type: "DASH_BUILDER_STREAM",
|
|
25939
|
+
from: { type: "data-agent" },
|
|
25940
|
+
to: { type: "runtime", id: wsId },
|
|
25941
|
+
payload: { dashboardId, seq: seq++, update }
|
|
25942
|
+
});
|
|
25943
|
+
} catch (err) {
|
|
25944
|
+
logger.warn(
|
|
25945
|
+
`[DashBuilderReq] Stream send failed (socket may be closed): ${err instanceof Error ? err.message : String(err)}`
|
|
25946
|
+
);
|
|
25947
|
+
}
|
|
25948
|
+
};
|
|
25949
|
+
try {
|
|
25950
|
+
const result = await collections["dashboard-builder-agent"]["prompt"]({
|
|
25951
|
+
dashboardId,
|
|
25952
|
+
text,
|
|
25953
|
+
panelId,
|
|
25954
|
+
projectId,
|
|
25955
|
+
userId,
|
|
25956
|
+
signal: abortController.signal,
|
|
25957
|
+
onUpdate: stream
|
|
25958
|
+
});
|
|
25959
|
+
respond(result ?? { started: true });
|
|
25960
|
+
} catch (err) {
|
|
25961
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
25962
|
+
logger.error(`[DashBuilderReq] ${dashboardId} failed to start: ${message}`);
|
|
25963
|
+
respond({ started: false, error: message });
|
|
25964
|
+
} finally {
|
|
25965
|
+
if (inFlightAborts4.get(dashboardId) === abortController) {
|
|
25966
|
+
inFlightAborts4.delete(dashboardId);
|
|
25967
|
+
}
|
|
25968
|
+
}
|
|
25969
|
+
}
|
|
25970
|
+
|
|
25265
25971
|
// src/reportComp/types.ts
|
|
25266
25972
|
var DEFAULT_REPORT_COMP_MODELS = {
|
|
25267
25973
|
anthropic: "anthropic/claude-haiku-4-5-20251001",
|
|
@@ -25760,21 +26466,21 @@ Fixed SQL query:`;
|
|
|
25760
26466
|
}
|
|
25761
26467
|
|
|
25762
26468
|
// src/reportComp/index.ts
|
|
25763
|
-
var
|
|
25764
|
-
var
|
|
25765
|
-
var
|
|
25766
|
-
function
|
|
26469
|
+
var inFlightAborts5 = /* @__PURE__ */ new Map();
|
|
26470
|
+
var recentlyAborted5 = /* @__PURE__ */ new Map();
|
|
26471
|
+
var ABORT_TOMBSTONE_TTL_MS5 = 3e4;
|
|
26472
|
+
function setAbortTombstone5(reportId) {
|
|
25767
26473
|
const now = Date.now();
|
|
25768
|
-
|
|
25769
|
-
for (const [key, ts] of
|
|
25770
|
-
if (now - ts >
|
|
26474
|
+
recentlyAborted5.set(reportId, now);
|
|
26475
|
+
for (const [key, ts] of recentlyAborted5) {
|
|
26476
|
+
if (now - ts > ABORT_TOMBSTONE_TTL_MS5) recentlyAborted5.delete(key);
|
|
25771
26477
|
}
|
|
25772
26478
|
}
|
|
25773
|
-
function
|
|
25774
|
-
const ts =
|
|
26479
|
+
function consumeAbortTombstone5(reportId) {
|
|
26480
|
+
const ts = recentlyAborted5.get(reportId);
|
|
25775
26481
|
if (ts === void 0) return false;
|
|
25776
|
-
|
|
25777
|
-
return Date.now() - ts <=
|
|
26482
|
+
recentlyAborted5.delete(reportId);
|
|
26483
|
+
return Date.now() - ts <= ABORT_TOMBSTONE_TTL_MS5;
|
|
25778
26484
|
}
|
|
25779
26485
|
function handleReportCompAbort(data, sendMessage) {
|
|
25780
26486
|
const parseResult = ReportCompAbortRequestMessageSchema.safeParse(data);
|
|
@@ -25785,13 +26491,13 @@ function handleReportCompAbort(data, sendMessage) {
|
|
|
25785
26491
|
const { payload, from } = parseResult.data;
|
|
25786
26492
|
const { reportId } = payload;
|
|
25787
26493
|
const wsId = from.id;
|
|
25788
|
-
const controller =
|
|
26494
|
+
const controller = inFlightAborts5.get(reportId);
|
|
25789
26495
|
if (controller) {
|
|
25790
26496
|
controller.abort();
|
|
25791
|
-
|
|
26497
|
+
inFlightAborts5.delete(reportId);
|
|
25792
26498
|
logger.info(`[ReportCompAbort] Aborted in-flight run for report ${reportId}`);
|
|
25793
26499
|
} else {
|
|
25794
|
-
|
|
26500
|
+
setAbortTombstone5(reportId);
|
|
25795
26501
|
logger.info(`[ReportCompAbort] No in-flight run for report ${reportId} \u2014 tombstoned`);
|
|
25796
26502
|
}
|
|
25797
26503
|
try {
|
|
@@ -25837,11 +26543,11 @@ var processReportCompRequest = async (data, components, _sendMessage, anthropicA
|
|
|
25837
26543
|
const trace = createRunTrace();
|
|
25838
26544
|
const abortController = new AbortController();
|
|
25839
26545
|
if (reportId) {
|
|
25840
|
-
if (
|
|
26546
|
+
if (consumeAbortTombstone5(reportId)) {
|
|
25841
26547
|
abortController.abort();
|
|
25842
26548
|
logger.info(`[REPORT_COMP_REQ] reportId=${reportId} was pre-aborted \u2014 starting cancelled`);
|
|
25843
26549
|
}
|
|
25844
|
-
|
|
26550
|
+
inFlightAborts5.set(reportId, abortController);
|
|
25845
26551
|
}
|
|
25846
26552
|
let llmResponse;
|
|
25847
26553
|
try {
|
|
@@ -25862,7 +26568,7 @@ var processReportCompRequest = async (data, components, _sendMessage, anthropicA
|
|
|
25862
26568
|
trace
|
|
25863
26569
|
);
|
|
25864
26570
|
} finally {
|
|
25865
|
-
if (reportId)
|
|
26571
|
+
if (reportId) inFlightAborts5.delete(reportId);
|
|
25866
26572
|
}
|
|
25867
26573
|
const wasAborted = abortController.signal.aborted || !llmResponse.success && Array.isArray(llmResponse.errors) && llmResponse.errors.includes("aborted");
|
|
25868
26574
|
if (wasAborted) {
|
|
@@ -26249,7 +26955,7 @@ function getLLMProviders() {
|
|
|
26249
26955
|
|
|
26250
26956
|
// src/auth/user-manager.ts
|
|
26251
26957
|
import fs12 from "fs";
|
|
26252
|
-
import
|
|
26958
|
+
import path13 from "path";
|
|
26253
26959
|
import os2 from "os";
|
|
26254
26960
|
var UserManager = class {
|
|
26255
26961
|
/**
|
|
@@ -26262,7 +26968,7 @@ var UserManager = class {
|
|
|
26262
26968
|
this.hasChanged = false;
|
|
26263
26969
|
this.syncInterval = null;
|
|
26264
26970
|
this.isInitialized = false;
|
|
26265
|
-
this.filePath =
|
|
26971
|
+
this.filePath = path13.join(os2.homedir(), ".superatom", "projects", projectId, "users.json");
|
|
26266
26972
|
this.syncIntervalMs = syncIntervalMs;
|
|
26267
26973
|
}
|
|
26268
26974
|
/**
|
|
@@ -26287,7 +26993,7 @@ var UserManager = class {
|
|
|
26287
26993
|
*/
|
|
26288
26994
|
async loadUsersFromFile() {
|
|
26289
26995
|
try {
|
|
26290
|
-
const dir =
|
|
26996
|
+
const dir = path13.dirname(this.filePath);
|
|
26291
26997
|
if (!fs12.existsSync(dir)) {
|
|
26292
26998
|
logger.info(`Creating directory structure: ${dir}`);
|
|
26293
26999
|
fs12.mkdirSync(dir, { recursive: true });
|
|
@@ -26319,7 +27025,7 @@ var UserManager = class {
|
|
|
26319
27025
|
return;
|
|
26320
27026
|
}
|
|
26321
27027
|
try {
|
|
26322
|
-
const dir =
|
|
27028
|
+
const dir = path13.dirname(this.filePath);
|
|
26323
27029
|
if (!fs12.existsSync(dir)) {
|
|
26324
27030
|
fs12.mkdirSync(dir, { recursive: true });
|
|
26325
27031
|
}
|
|
@@ -26547,7 +27253,7 @@ var UserManager = class {
|
|
|
26547
27253
|
|
|
26548
27254
|
// src/dashboards/dashboard-manager.ts
|
|
26549
27255
|
import fs13 from "fs";
|
|
26550
|
-
import
|
|
27256
|
+
import path14 from "path";
|
|
26551
27257
|
import os3 from "os";
|
|
26552
27258
|
var DashboardManager = class {
|
|
26553
27259
|
/**
|
|
@@ -26556,7 +27262,7 @@ var DashboardManager = class {
|
|
|
26556
27262
|
*/
|
|
26557
27263
|
constructor(projectId = "snowflake-dataset") {
|
|
26558
27264
|
this.projectId = projectId;
|
|
26559
|
-
this.dashboardsBasePath =
|
|
27265
|
+
this.dashboardsBasePath = path14.join(
|
|
26560
27266
|
os3.homedir(),
|
|
26561
27267
|
".superatom",
|
|
26562
27268
|
"projects",
|
|
@@ -26570,7 +27276,7 @@ var DashboardManager = class {
|
|
|
26570
27276
|
* @returns Full path to dashboard data.json file
|
|
26571
27277
|
*/
|
|
26572
27278
|
getDashboardPath(dashboardId) {
|
|
26573
|
-
return
|
|
27279
|
+
return path14.join(this.dashboardsBasePath, dashboardId, "data.json");
|
|
26574
27280
|
}
|
|
26575
27281
|
/**
|
|
26576
27282
|
* Create a new dashboard
|
|
@@ -26580,7 +27286,7 @@ var DashboardManager = class {
|
|
|
26580
27286
|
*/
|
|
26581
27287
|
createDashboard(dashboardId, dashboard) {
|
|
26582
27288
|
const dashboardPath = this.getDashboardPath(dashboardId);
|
|
26583
|
-
const dashboardDir =
|
|
27289
|
+
const dashboardDir = path14.dirname(dashboardPath);
|
|
26584
27290
|
if (fs13.existsSync(dashboardPath)) {
|
|
26585
27291
|
throw new Error(`Dashboard '${dashboardId}' already exists`);
|
|
26586
27292
|
}
|
|
@@ -26668,7 +27374,7 @@ var DashboardManager = class {
|
|
|
26668
27374
|
*/
|
|
26669
27375
|
deleteDashboard(dashboardId) {
|
|
26670
27376
|
const dashboardPath = this.getDashboardPath(dashboardId);
|
|
26671
|
-
const dashboardDir =
|
|
27377
|
+
const dashboardDir = path14.dirname(dashboardPath);
|
|
26672
27378
|
if (!fs13.existsSync(dashboardPath)) {
|
|
26673
27379
|
logger.warn(`Dashboard not found for deletion: ${dashboardId}`);
|
|
26674
27380
|
return false;
|
|
@@ -26714,7 +27420,7 @@ var DashboardManager = class {
|
|
|
26714
27420
|
|
|
26715
27421
|
// src/reports/report-manager.ts
|
|
26716
27422
|
import fs14 from "fs";
|
|
26717
|
-
import
|
|
27423
|
+
import path15 from "path";
|
|
26718
27424
|
import os4 from "os";
|
|
26719
27425
|
var ReportManager = class {
|
|
26720
27426
|
/**
|
|
@@ -26723,7 +27429,7 @@ var ReportManager = class {
|
|
|
26723
27429
|
*/
|
|
26724
27430
|
constructor(projectId = "snowflake-dataset") {
|
|
26725
27431
|
this.projectId = projectId;
|
|
26726
|
-
this.reportsBasePath =
|
|
27432
|
+
this.reportsBasePath = path15.join(
|
|
26727
27433
|
os4.homedir(),
|
|
26728
27434
|
".superatom",
|
|
26729
27435
|
"projects",
|
|
@@ -26737,7 +27443,7 @@ var ReportManager = class {
|
|
|
26737
27443
|
* @returns Full path to report data.json file
|
|
26738
27444
|
*/
|
|
26739
27445
|
getReportPath(reportId) {
|
|
26740
|
-
return
|
|
27446
|
+
return path15.join(this.reportsBasePath, reportId, "data.json");
|
|
26741
27447
|
}
|
|
26742
27448
|
/**
|
|
26743
27449
|
* Create a new report
|
|
@@ -26747,7 +27453,7 @@ var ReportManager = class {
|
|
|
26747
27453
|
*/
|
|
26748
27454
|
createReport(reportId, report) {
|
|
26749
27455
|
const reportPath = this.getReportPath(reportId);
|
|
26750
|
-
const reportDir =
|
|
27456
|
+
const reportDir = path15.dirname(reportPath);
|
|
26751
27457
|
if (fs14.existsSync(reportPath)) {
|
|
26752
27458
|
throw new Error(`Report '${reportId}' already exists`);
|
|
26753
27459
|
}
|
|
@@ -26835,7 +27541,7 @@ var ReportManager = class {
|
|
|
26835
27541
|
*/
|
|
26836
27542
|
deleteReport(reportId) {
|
|
26837
27543
|
const reportPath = this.getReportPath(reportId);
|
|
26838
|
-
const reportDir =
|
|
27544
|
+
const reportDir = path15.dirname(reportPath);
|
|
26839
27545
|
if (!fs14.existsSync(reportPath)) {
|
|
26840
27546
|
logger.warn(`Report not found for deletion: ${reportId}`);
|
|
26841
27547
|
return false;
|
|
@@ -27364,7 +28070,7 @@ var CleanupService = class _CleanupService {
|
|
|
27364
28070
|
};
|
|
27365
28071
|
|
|
27366
28072
|
// src/dashboardAgent/collection.ts
|
|
27367
|
-
import
|
|
28073
|
+
import path16 from "path";
|
|
27368
28074
|
import fs15 from "fs";
|
|
27369
28075
|
|
|
27370
28076
|
// src/dashboardAgent/tools.ts
|
|
@@ -27571,16 +28277,16 @@ function buildDashboardAgentTools(sdk, signal, trace) {
|
|
|
27571
28277
|
}
|
|
27572
28278
|
|
|
27573
28279
|
// src/dashboardAgent/collection.ts
|
|
27574
|
-
var
|
|
27575
|
-
var
|
|
27576
|
-
function
|
|
27577
|
-
if (!
|
|
27578
|
-
return
|
|
27579
|
-
}
|
|
27580
|
-
var
|
|
27581
|
-
function
|
|
27582
|
-
if (!
|
|
27583
|
-
|
|
28280
|
+
var dynamicImport3 = new Function("specifier", "return import(specifier)");
|
|
28281
|
+
var piModulePromise2 = null;
|
|
28282
|
+
function loadPi2() {
|
|
28283
|
+
if (!piModulePromise2) piModulePromise2 = dynamicImport3("@earendil-works/pi-coding-agent");
|
|
28284
|
+
return piModulePromise2;
|
|
28285
|
+
}
|
|
28286
|
+
var authAndRegistry2 = null;
|
|
28287
|
+
function getAuthAndRegistry2() {
|
|
28288
|
+
if (!authAndRegistry2) {
|
|
28289
|
+
authAndRegistry2 = loadPi2().then(({ AuthStorage, ModelRegistry }) => {
|
|
27584
28290
|
const authStorage = AuthStorage.create();
|
|
27585
28291
|
const modelRegistry = ModelRegistry.create(authStorage);
|
|
27586
28292
|
const proxyRoot = process.env.SUPERATOM_LLM_PROXY_URL;
|
|
@@ -27597,7 +28303,7 @@ function getAuthAndRegistry() {
|
|
|
27597
28303
|
return { authStorage, modelRegistry };
|
|
27598
28304
|
});
|
|
27599
28305
|
}
|
|
27600
|
-
return
|
|
28306
|
+
return authAndRegistry2;
|
|
27601
28307
|
}
|
|
27602
28308
|
async function preResolveSchema(sdk, tool, intent, projectId) {
|
|
27603
28309
|
const tier = tool.schemaTier;
|
|
@@ -27693,12 +28399,12 @@ function textDelta(event) {
|
|
|
27693
28399
|
}
|
|
27694
28400
|
var runningDashboards = /* @__PURE__ */ new Set();
|
|
27695
28401
|
function registerDashboardAgentCollection(sdk, config2 = {}) {
|
|
27696
|
-
const piCwd = config2.cwd || process.env.PI_AGENT_DIR ||
|
|
27697
|
-
const runtimeDir = config2.runtimeDir || process.env.PI_AGENT_RUNTIME_DIR ||
|
|
28402
|
+
const piCwd = config2.cwd || process.env.PI_AGENT_DIR || path16.join(process.cwd(), ".prompts", "dashboard-agent");
|
|
28403
|
+
const runtimeDir = config2.runtimeDir || process.env.PI_AGENT_RUNTIME_DIR || path16.join(process.cwd(), ".pi-dashboard-agent-runtime");
|
|
27698
28404
|
const freshSession = config2.freshSession ?? process.env.PI_AGENT_FRESH_SESSION !== "false";
|
|
27699
|
-
const SESSIONS_FILE =
|
|
27700
|
-
const DRAFTS_DIR =
|
|
27701
|
-
const DASHBOARD_LOG_FILE =
|
|
28405
|
+
const SESSIONS_FILE = path16.join(runtimeDir, ".pi-dashboard-sessions.json");
|
|
28406
|
+
const DRAFTS_DIR = path16.join(runtimeDir, "drafts");
|
|
28407
|
+
const DASHBOARD_LOG_FILE = path16.join(runtimeDir, "dashboard.log");
|
|
27702
28408
|
function appendLog(text) {
|
|
27703
28409
|
try {
|
|
27704
28410
|
fs15.mkdirSync(runtimeDir, { recursive: true });
|
|
@@ -27722,7 +28428,7 @@ ${fullPrompt}
|
|
|
27722
28428
|
}
|
|
27723
28429
|
function readDraft(dashboardId) {
|
|
27724
28430
|
try {
|
|
27725
|
-
const raw = fs15.readFileSync(
|
|
28431
|
+
const raw = fs15.readFileSync(path16.join(DRAFTS_DIR, `${dashboardId}.json`), "utf-8");
|
|
27726
28432
|
return JSON.parse(raw);
|
|
27727
28433
|
} catch (err) {
|
|
27728
28434
|
console.warn(`[DashboardAgent] Failed to read draft for ${dashboardId}: ${err?.message ?? err}`);
|
|
@@ -27810,8 +28516,8 @@ ${fullPrompt}
|
|
|
27810
28516
|
return { success: false, error: "aborted" };
|
|
27811
28517
|
}
|
|
27812
28518
|
try {
|
|
27813
|
-
const { createAgentSession, SessionManager } = await
|
|
27814
|
-
const { authStorage, modelRegistry } = await
|
|
28519
|
+
const { createAgentSession, SessionManager } = await loadPi2();
|
|
28520
|
+
const { authStorage, modelRegistry } = await getAuthAndRegistry2();
|
|
27815
28521
|
let model;
|
|
27816
28522
|
const explicitProvider = config2.provider || process.env.PI_AGENT_PROVIDER;
|
|
27817
28523
|
const explicitModel = config2.model || process.env.PI_AGENT_MODEL;
|
|
@@ -27917,7 +28623,7 @@ ${turn.responseText ?? ""}`).join("\n\n");
|
|
|
27917
28623
|
console.warn(`[DashboardAgent] Failed to fetch previous responses for ${dashboardId}: ${err?.message ?? err}`);
|
|
27918
28624
|
}
|
|
27919
28625
|
}
|
|
27920
|
-
const draftPath =
|
|
28626
|
+
const draftPath = path16.join(DRAFTS_DIR, `${dashboardId}.json`);
|
|
27921
28627
|
const fullPrompt = [
|
|
27922
28628
|
`Dashboard ID: ${dashboardId}.`,
|
|
27923
28629
|
projectId ? `Project ID: ${projectId}.` : null,
|
|
@@ -28209,6 +28915,15 @@ var SuperatomSDK = class {
|
|
|
28209
28915
|
// since an outage of unknown length shouldn't grow this without limit.
|
|
28210
28916
|
this.pendingOutbox = [];
|
|
28211
28917
|
this.MAX_OUTBOX_SIZE = 50;
|
|
28918
|
+
/**
|
|
28919
|
+
* The dashboard contract, as registered by the browser bundle that holds it.
|
|
28920
|
+
*
|
|
28921
|
+
* Empty until a client has connected and pushed it. That is a real state and
|
|
28922
|
+
* callers must handle it rather than treat it as an empty contract: an empty
|
|
28923
|
+
* list means "nobody has told us yet", not "there are no components", and
|
|
28924
|
+
* building against it would produce a dashboard that can import nothing.
|
|
28925
|
+
*/
|
|
28926
|
+
this.dashContract = [];
|
|
28212
28927
|
if (config2.logLevel) {
|
|
28213
28928
|
logger.setLogLevel(config2.logLevel);
|
|
28214
28929
|
}
|
|
@@ -28325,7 +29040,7 @@ var SuperatomSDK = class {
|
|
|
28325
29040
|
logger.info("Already connected to WebSocket");
|
|
28326
29041
|
return Promise.resolve();
|
|
28327
29042
|
}
|
|
28328
|
-
return new Promise((
|
|
29043
|
+
return new Promise((resolve3, reject) => {
|
|
28329
29044
|
try {
|
|
28330
29045
|
const url = new URL(this.url);
|
|
28331
29046
|
if (this.apiKey) {
|
|
@@ -28341,7 +29056,7 @@ var SuperatomSDK = class {
|
|
|
28341
29056
|
logger.info("WebSocket connected successfully");
|
|
28342
29057
|
this.startHeartbeat();
|
|
28343
29058
|
this.flushPendingOutbox();
|
|
28344
|
-
|
|
29059
|
+
resolve3();
|
|
28345
29060
|
});
|
|
28346
29061
|
this.ws.addEventListener("message", (event) => {
|
|
28347
29062
|
this.handleMessage(event.data);
|
|
@@ -28429,6 +29144,13 @@ var SuperatomSDK = class {
|
|
|
28429
29144
|
logger.error("Failed to handle component list request:", error);
|
|
28430
29145
|
});
|
|
28431
29146
|
break;
|
|
29147
|
+
/* The dashboard contract, pushed by the bundle that holds it — on
|
|
29148
|
+
* connect and again on every reconnect. See types.ts. */
|
|
29149
|
+
case "DASH_CONTRACT_RES":
|
|
29150
|
+
handleDashContractResponse(parsed, (c) => this.storeDashContract(c), this.collections).catch((error) => {
|
|
29151
|
+
logger.error("Failed to handle dashboard contract:", error);
|
|
29152
|
+
});
|
|
29153
|
+
break;
|
|
28432
29154
|
case "WORKFLOW_LIST_RES":
|
|
28433
29155
|
handleWorkflowListResponse(parsed, (wf) => this.setWorkflows(wf)).catch((error) => {
|
|
28434
29156
|
logger.error("Failed to handle workflow list request:", error);
|
|
@@ -28495,6 +29217,16 @@ var SuperatomSDK = class {
|
|
|
28495
29217
|
case "CODING_AGENT_ABORT_REQ":
|
|
28496
29218
|
handleCodingAgentAbort(parsed, (msg) => this.send(msg));
|
|
28497
29219
|
break;
|
|
29220
|
+
// The dashboard BUILDER's conversation — distinct from
|
|
29221
|
+
// DASHBOARD_AGENT_REQ, which drives the older JSON-DSL flow.
|
|
29222
|
+
case "DASH_BUILDER_REQ":
|
|
29223
|
+
handleDashBuilderRequest(parsed, this.collections, (msg) => this.send(msg)).catch((error) => {
|
|
29224
|
+
logger.error("Failed to handle dash builder request:", error);
|
|
29225
|
+
});
|
|
29226
|
+
break;
|
|
29227
|
+
case "DASH_BUILDER_ABORT_REQ":
|
|
29228
|
+
handleDashBuilderAbort(parsed, (msg) => this.send(msg));
|
|
29229
|
+
break;
|
|
28498
29230
|
case "REPORT_COMP_REQ":
|
|
28499
29231
|
handleReportCompRequest(parsed, this.components, (msg) => this.send(msg), this.anthropicApiKey, this.groqApiKey, this.geminiApiKey, this.openaiApiKey, this.llmProviders, this.collections, this.tools, this.dashCompModels).catch((error) => {
|
|
28500
29232
|
logger.error("Failed to handle report comp request:", error);
|
|
@@ -28717,6 +29449,14 @@ var SuperatomSDK = class {
|
|
|
28717
29449
|
getComponents() {
|
|
28718
29450
|
return this.components;
|
|
28719
29451
|
}
|
|
29452
|
+
storeDashContract(components) {
|
|
29453
|
+
this.dashContract = components;
|
|
29454
|
+
logger.info(`Dashboard contract registered: ${components.length} components`);
|
|
29455
|
+
}
|
|
29456
|
+
/** The registered dashboard contract. Empty means "not registered yet". */
|
|
29457
|
+
getDashContract() {
|
|
29458
|
+
return this.dashContract;
|
|
29459
|
+
}
|
|
28720
29460
|
/**
|
|
28721
29461
|
* Set tools for the SDK instance
|
|
28722
29462
|
*/
|
|
@@ -28838,11 +29578,13 @@ export {
|
|
|
28838
29578
|
UIBlock,
|
|
28839
29579
|
UILogCollector,
|
|
28840
29580
|
UserManager,
|
|
29581
|
+
analyticsClient,
|
|
28841
29582
|
answerCatalogForBinding,
|
|
28842
29583
|
answerComponents,
|
|
28843
29584
|
anthropicLLM,
|
|
28844
29585
|
assertReadOnlySql,
|
|
28845
29586
|
bindContext,
|
|
29587
|
+
bridgePreamble,
|
|
28846
29588
|
captureContext,
|
|
28847
29589
|
clearContextTokens,
|
|
28848
29590
|
contextTokenCount,
|
|
@@ -28858,6 +29600,7 @@ export {
|
|
|
28858
29600
|
geminiLLM,
|
|
28859
29601
|
getCodingAgent,
|
|
28860
29602
|
getCodingAgentsConfig,
|
|
29603
|
+
getPiSessionState,
|
|
28861
29604
|
getRequestContext,
|
|
28862
29605
|
groqLLM,
|
|
28863
29606
|
hybridRerank,
|
|
@@ -28870,9 +29613,11 @@ export {
|
|
|
28870
29613
|
mintContextToken,
|
|
28871
29614
|
normalizeScriptBody,
|
|
28872
29615
|
onAgentRun,
|
|
29616
|
+
onPiSessionUpdate,
|
|
28873
29617
|
openaiLLM,
|
|
28874
29618
|
policiesFromConfig,
|
|
28875
29619
|
projectForDatasetBinding,
|
|
29620
|
+
promptLoader,
|
|
28876
29621
|
queryCache,
|
|
28877
29622
|
registerCodingAgentCollection,
|
|
28878
29623
|
registerCodingAgents,
|
|
@@ -28894,6 +29639,7 @@ export {
|
|
|
28894
29639
|
userPromptErrorLogger,
|
|
28895
29640
|
validateComponentSpec,
|
|
28896
29641
|
withCapturedContext,
|
|
28897
|
-
writeBridgeShims
|
|
29642
|
+
writeBridgeShims,
|
|
29643
|
+
writeShims
|
|
28898
29644
|
};
|
|
28899
29645
|
//# sourceMappingURL=index.mjs.map
|