@songsid/agend 2.3.0-beta.10 → 2.3.0-beta.12
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/dist/agent-whats-new.js +14 -9
- package/dist/agent-whats-new.js.map +1 -1
- package/dist/channel/adapters/discord-client-retirement.d.ts +5 -0
- package/dist/channel/adapters/discord-client-retirement.js +57 -0
- package/dist/channel/adapters/discord-client-retirement.js.map +1 -0
- package/dist/channel/adapters/discord.d.ts +2 -0
- package/dist/channel/adapters/discord.js +14 -4
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/cli.js +12 -79
- package/dist/cli.js.map +1 -1
- package/dist/daemon.d.ts +3 -0
- package/dist/daemon.js +25 -0
- package/dist/daemon.js.map +1 -1
- package/dist/fleet-manager.d.ts +8 -1
- package/dist/fleet-manager.js +101 -33
- package/dist/fleet-manager.js.map +1 -1
- package/dist/fleet-process-handlers.d.ts +18 -0
- package/dist/fleet-process-handlers.js +69 -0
- package/dist/fleet-process-handlers.js.map +1 -0
- package/dist/general-knowledge/skills/web-appearance/SKILL.md +1 -1
- package/dist/general-knowledge/skills/web-dashboard/SKILL.md +8 -2
- package/dist/instance-lifecycle.d.ts +2 -0
- package/dist/instance-lifecycle.js +11 -6
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/outbound-schemas.js +1 -1
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/settings-api.d.ts +4 -0
- package/dist/settings-api.js +23 -0
- package/dist/settings-api.js.map +1 -1
- package/dist/ui/app-effects.js +13 -1
- package/dist/ui/chat-render.js +16 -1
- package/dist/ui/chat-store.js +32 -10
- package/dist/ui/chat-strings.js +16 -0
- package/dist/ui/chat-thread.js +14 -1
- package/dist/ui/panel-chat.js +57 -9
- package/dist/ui/panel-fleet.js +2 -1
- package/dist/ui/panel-settings.js +24 -0
- package/dist/ui/settings-strings.js +2 -0
- package/dist/ui/shared/app-i18n.js +1 -1
- package/dist/ui/shared/app-route.js +18 -0
- package/dist/ui/shared/app-shell.js +17 -18
- package/dist/ui/shared/app.css +1 -1
- package/dist/ui/shared/effect-owner-source.js +8 -1
- package/dist/ui/shared/effect-registry.js +10 -2
- package/dist/ui/shared/owner-css.js +30 -1
- package/dist/web-api.d.ts +6 -2
- package/dist/web-api.js +50 -14
- package/dist/web-api.js.map +1 -1
- package/dist/web-chat-history.d.ts +4 -0
- package/dist/web-chat-history.js +7 -2
- package/dist/web-chat-history.js.map +1 -1
- package/dist/web-image-meta.d.ts +13 -0
- package/dist/web-image-meta.js +62 -0
- package/dist/web-image-meta.js.map +1 -1
- package/dist/web-owner-css-store.d.ts +43 -1
- package/dist/web-owner-css-store.js +65 -9
- package/dist/web-owner-css-store.js.map +1 -1
- package/dist/web-settings-tools.js +7 -4
- package/dist/web-settings-tools.js.map +1 -1
- package/dist/web-upload.d.ts +13 -0
- package/dist/web-upload.js +39 -3
- package/dist/web-upload.js.map +1 -1
- package/package.json +1 -1
package/dist/fleet-manager.d.ts
CHANGED
|
@@ -411,6 +411,7 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
411
411
|
/** #2175: this boot's progress message, whose completion may still be owed by its background retry. */
|
|
412
412
|
private startupProgress;
|
|
413
413
|
private adapterState;
|
|
414
|
+
private adapterRetryInFlight;
|
|
414
415
|
/** Web Settings secret rotation is deliberately separate from reconnect
|
|
415
416
|
* recovery: a rotation must build a fresh provider client with the new token,
|
|
416
417
|
* and stale callbacks from the old client must not win. */
|
|
@@ -1683,8 +1684,14 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
1683
1684
|
private sweepOrphanedWebUploads;
|
|
1684
1685
|
/** Start the shared channel adapter(s) for topic mode */
|
|
1685
1686
|
private startSharedAdapter;
|
|
1686
|
-
/**
|
|
1687
|
+
/** Keep trying while the fleet runs, with a five-minute cap even after a long outage. */
|
|
1687
1688
|
private scheduleAdapterRetry;
|
|
1689
|
+
/** One login per connection, shared by the background timer and the operator's Retry now. */
|
|
1690
|
+
private attemptAdapterRetry;
|
|
1691
|
+
retryAdapterNow(adapterId: string): {
|
|
1692
|
+
queued: boolean;
|
|
1693
|
+
already_running?: boolean;
|
|
1694
|
+
};
|
|
1688
1695
|
/** Notify admin about adapter failure (uses any available adapter). */
|
|
1689
1696
|
private notifyAdapterFailure;
|
|
1690
1697
|
/** Notify admin that a retried adapter reconnected. */
|
package/dist/fleet-manager.js
CHANGED
|
@@ -784,6 +784,7 @@ export class FleetManager {
|
|
|
784
784
|
/** #2175: this boot's progress message, whose completion may still be owed by its background retry. */
|
|
785
785
|
startupProgress = null;
|
|
786
786
|
adapterState = new Map();
|
|
787
|
+
adapterRetryInFlight = new Map();
|
|
787
788
|
/** Web Settings secret rotation is deliberately separate from reconnect
|
|
788
789
|
* recovery: a rotation must build a fresh provider client with the new token,
|
|
789
790
|
* and stale callbacks from the old client must not win. */
|
|
@@ -7537,48 +7538,109 @@ export class FleetManager {
|
|
|
7537
7538
|
const err = results[i].reason;
|
|
7538
7539
|
this.logger.error({ adapterId, err: err?.message ?? err }, "Adapter startup failed — scheduling background retry");
|
|
7539
7540
|
this.adapterState.set(adapterId, { status: "retrying", retryCount: 0, lastError: err?.message ?? String(err) });
|
|
7540
|
-
this.scheduleAdapterRetry(adapterId
|
|
7541
|
+
this.scheduleAdapterRetry(adapterId);
|
|
7541
7542
|
// Notify admin via whichever adapter is already up
|
|
7542
7543
|
this.notifyAdapterFailure(adapterId, err?.message ?? String(err));
|
|
7543
7544
|
}
|
|
7544
7545
|
}
|
|
7545
7546
|
}
|
|
7546
|
-
/**
|
|
7547
|
-
scheduleAdapterRetry(adapterId
|
|
7548
|
-
const MAX_RETRIES = 10;
|
|
7547
|
+
/** Keep trying while the fleet runs, with a five-minute cap even after a long outage. */
|
|
7548
|
+
scheduleAdapterRetry(adapterId) {
|
|
7549
7549
|
const INITIAL_DELAY_MS = 5_000;
|
|
7550
7550
|
const MAX_DELAY_MS = 5 * 60_000;
|
|
7551
7551
|
const state = this.adapterState.get(adapterId);
|
|
7552
|
-
if (!state || state.
|
|
7553
|
-
if (state) {
|
|
7554
|
-
state.status = "failed";
|
|
7555
|
-
this.logger.error({ adapterId, retries: state.retryCount }, "Adapter retry exhausted — giving up");
|
|
7556
|
-
this.notifyAdapterFailure(adapterId, `Retry exhausted after ${state.retryCount} attempts. Check token/network and restart fleet.`);
|
|
7557
|
-
}
|
|
7552
|
+
if (this.shuttingDown || !state || state.retryTimer || this.adapterRetryInFlight.has(adapterId))
|
|
7558
7553
|
return;
|
|
7559
|
-
|
|
7560
|
-
const delay = Math.min(INITIAL_DELAY_MS * Math.pow(2, state.retryCount), MAX_DELAY_MS);
|
|
7554
|
+
const delay = Math.min(INITIAL_DELAY_MS * Math.pow(2, Math.min(state.retryCount, 6)), MAX_DELAY_MS);
|
|
7561
7555
|
this.logger.info({ adapterId, attempt: state.retryCount + 1, delay_ms: delay }, "Scheduling adapter retry");
|
|
7562
|
-
|
|
7556
|
+
const timer = setTimeout(() => {
|
|
7557
|
+
const current = this.adapterState.get(adapterId);
|
|
7558
|
+
if (this.shuttingDown || current?.retryTimer !== timer)
|
|
7559
|
+
return;
|
|
7560
|
+
current.retryTimer = undefined;
|
|
7561
|
+
void this.attemptAdapterRetry(adapterId);
|
|
7562
|
+
}, delay);
|
|
7563
|
+
state.retryTimer = timer;
|
|
7564
|
+
timer.unref?.();
|
|
7565
|
+
}
|
|
7566
|
+
/** One login per connection, shared by the background timer and the operator's Retry now. */
|
|
7567
|
+
attemptAdapterRetry(adapterId) {
|
|
7568
|
+
const pending = this.adapterRetryInFlight.get(adapterId);
|
|
7569
|
+
if (pending)
|
|
7570
|
+
return pending;
|
|
7571
|
+
if (this.shuttingDown || !this.secureConnectionChannel(adapterId))
|
|
7572
|
+
return Promise.resolve();
|
|
7573
|
+
const attempt = Promise.resolve().then(async () => {
|
|
7574
|
+
const channel = this.secureConnectionChannel(adapterId);
|
|
7575
|
+
if (this.shuttingDown || !channel)
|
|
7576
|
+
return;
|
|
7577
|
+
const generation = this.settingsGeneration;
|
|
7578
|
+
const binding = JSON.stringify([channel, this.getPrimaryAdapterId()]);
|
|
7579
|
+
const token = process.env[channel.bot_token_env];
|
|
7580
|
+
const operation = { owner: Symbol("adapter-retry"), assert: () => {
|
|
7581
|
+
if (this.shuttingDown || generation !== this.settingsGeneration
|
|
7582
|
+
|| JSON.stringify([this.secureConnectionChannel(adapterId), this.getPrimaryAdapterId()]) !== binding
|
|
7583
|
+
|| process.env[channel.bot_token_env] !== token)
|
|
7584
|
+
throw new Error("adapter retry superseded");
|
|
7585
|
+
} };
|
|
7586
|
+
const state = this.adapterState.get(adapterId) ?? { status: "retrying", retryCount: 0 };
|
|
7587
|
+
state.status = "retrying";
|
|
7563
7588
|
state.retryCount++;
|
|
7589
|
+
this.adapterState.set(adapterId, state);
|
|
7564
7590
|
try {
|
|
7565
|
-
if (
|
|
7566
|
-
await this.startSingleAdapter(
|
|
7567
|
-
|
|
7568
|
-
|
|
7569
|
-
|
|
7570
|
-
|
|
7571
|
-
|
|
7572
|
-
|
|
7591
|
+
if (this.getPrimaryAdapterId() === adapterId)
|
|
7592
|
+
await this.startSingleAdapter(this.fleetConfig, channel, undefined, operation);
|
|
7593
|
+
else
|
|
7594
|
+
await this.startAdditionalAdapter(channel, true, undefined, operation);
|
|
7595
|
+
if (this.shuttingDown || generation !== this.settingsGeneration)
|
|
7596
|
+
return;
|
|
7597
|
+
if (!this.adapters.has(adapterId))
|
|
7598
|
+
throw new Error("Adapter token is not configured");
|
|
7599
|
+
// Health events can replace the state object during login. Update its current owner.
|
|
7600
|
+
const current = this.adapterState.get(adapterId);
|
|
7601
|
+
current.status = "connected";
|
|
7602
|
+
current.lastError = undefined;
|
|
7573
7603
|
this.logger.info({ adapterId, attempts: state.retryCount }, "Adapter reconnected on retry");
|
|
7574
7604
|
this.notifyAdapterRecovery(adapterId, state.retryCount);
|
|
7575
7605
|
}
|
|
7576
7606
|
catch (err) {
|
|
7577
|
-
|
|
7578
|
-
|
|
7579
|
-
this.
|
|
7607
|
+
if (this.shuttingDown || generation !== this.settingsGeneration)
|
|
7608
|
+
return;
|
|
7609
|
+
const current = this.adapterState.get(adapterId);
|
|
7610
|
+
current.status = "retrying";
|
|
7611
|
+
current.lastError = err?.message ?? String(err);
|
|
7612
|
+
this.logger.warn({ adapterId, attempt: state.retryCount, err: current.lastError }, "Adapter retry failed");
|
|
7580
7613
|
}
|
|
7581
|
-
}
|
|
7614
|
+
}).finally(() => {
|
|
7615
|
+
if (this.adapterRetryInFlight.get(adapterId) !== attempt)
|
|
7616
|
+
return;
|
|
7617
|
+
this.adapterRetryInFlight.delete(adapterId);
|
|
7618
|
+
const channel = this.secureConnectionChannel(adapterId);
|
|
7619
|
+
if (!this.shuttingDown && channel && this.adapterState.get(adapterId)?.status !== "connected") {
|
|
7620
|
+
this.scheduleAdapterRetry(adapterId);
|
|
7621
|
+
}
|
|
7622
|
+
});
|
|
7623
|
+
this.adapterRetryInFlight.set(adapterId, attempt);
|
|
7624
|
+
return attempt;
|
|
7625
|
+
}
|
|
7626
|
+
retryAdapterNow(adapterId) {
|
|
7627
|
+
if (this.shuttingDown)
|
|
7628
|
+
throw new Error("The fleet is stopping");
|
|
7629
|
+
if (!this.secureConnectionChannel(adapterId))
|
|
7630
|
+
throw new Error("Connection not found");
|
|
7631
|
+
if (this.adapterRetryInFlight.has(adapterId) || this.adapterRestarting.has(adapterId))
|
|
7632
|
+
return { queued: true, already_running: true };
|
|
7633
|
+
const state = this.adapterState.get(adapterId);
|
|
7634
|
+
if (state?.retryTimer) {
|
|
7635
|
+
clearTimeout(state.retryTimer);
|
|
7636
|
+
state.retryTimer = undefined;
|
|
7637
|
+
}
|
|
7638
|
+
const adapter = this.adapters.get(adapterId);
|
|
7639
|
+
if (adapter && this.connectionStatus(adapterId, state, this.worlds.get(adapterId)).status === "connected")
|
|
7640
|
+
return { queued: false };
|
|
7641
|
+
const run = adapter ? this.restartAdapter(adapter, adapterId) : this.attemptAdapterRetry(adapterId);
|
|
7642
|
+
void run.catch(err => this.logger.warn({ adapterId, err }, "Requested adapter retry failed"));
|
|
7643
|
+
return { queued: true };
|
|
7582
7644
|
}
|
|
7583
7645
|
/** Notify admin about adapter failure (uses any available adapter). */
|
|
7584
7646
|
notifyAdapterFailure(adapterId, error) {
|
|
@@ -7633,6 +7695,7 @@ export class FleetManager {
|
|
|
7633
7695
|
: snapshot.status === "stopped" ? "failed"
|
|
7634
7696
|
: "retrying";
|
|
7635
7697
|
this.adapterState.set(adapterId, {
|
|
7698
|
+
...previous,
|
|
7636
7699
|
status,
|
|
7637
7700
|
retryCount: previous?.retryCount ?? 0,
|
|
7638
7701
|
lastError: status === "connected" ? undefined : snapshot.lastReconnectReason ?? previous?.lastError,
|
|
@@ -9458,6 +9521,16 @@ export class FleetManager {
|
|
|
9458
9521
|
respond(null, permitted.message);
|
|
9459
9522
|
return;
|
|
9460
9523
|
}
|
|
9524
|
+
// Fleet tools resolve their own targets. A missing chat world must not prevent local
|
|
9525
|
+
// delivery, inspection or receipt lookup; only channel tools need reply routing below.
|
|
9526
|
+
const handler = outboundHandlers.get(tool);
|
|
9527
|
+
if (handler && !usesChannelAddress(tool)) {
|
|
9528
|
+
this.eventLog?.logActivity("tool_call", senderSessionName ?? instanceName, this.summarizeToolCall(tool, args));
|
|
9529
|
+
await handler(this, args, respond, {
|
|
9530
|
+
instanceName, requestId, fleetRequestId, senderSessionName, operationId, sourceDaemonBootId,
|
|
9531
|
+
});
|
|
9532
|
+
return;
|
|
9533
|
+
}
|
|
9461
9534
|
// A fleet with no chat platform at all is driven from the web dashboard alone: a reply has nowhere
|
|
9462
9535
|
// else to go, and "retry shortly" would have the agent retry forever. It goes to the web chat.
|
|
9463
9536
|
const webOnlyReply = tool === "reply" && this.worlds.size === 0 && this.isWebOnlyFleet();
|
|
@@ -9649,19 +9722,14 @@ export class FleetManager {
|
|
|
9649
9722
|
if (routeToolCall(outAdapter, tool, args, threadId, respond)) {
|
|
9650
9723
|
return;
|
|
9651
9724
|
}
|
|
9652
|
-
// Log tool calls for activity visualization
|
|
9653
|
-
const senderLabel = senderSessionName ?? instanceName;
|
|
9654
|
-
this.eventLog?.logActivity("tool_call", senderLabel, this.summarizeToolCall(tool, args));
|
|
9655
|
-
// Dispatch fleet-specific tools via handler map
|
|
9656
|
-
const handler = outboundHandlers.get(tool);
|
|
9657
9725
|
if (handler) {
|
|
9726
|
+
this.eventLog?.logActivity("tool_call", senderSessionName ?? instanceName, this.summarizeToolCall(tool, args));
|
|
9658
9727
|
await handler(this, args, respond, {
|
|
9659
9728
|
instanceName, requestId, fleetRequestId, senderSessionName, operationId, sourceDaemonBootId,
|
|
9660
9729
|
});
|
|
9661
9730
|
}
|
|
9662
|
-
else
|
|
9731
|
+
else
|
|
9663
9732
|
respond(null, `Unknown tool: ${tool}`);
|
|
9664
|
-
}
|
|
9665
9733
|
}
|
|
9666
9734
|
/** Side effects of a routed reply: cancel-button lifecycle, logs, SSE, chat log. */
|
|
9667
9735
|
/** No chat platform is configured at all: the web dashboard is the fleet's only surface. */
|
|
@@ -20493,7 +20561,7 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
20493
20561
|
all = false;
|
|
20494
20562
|
const message = err?.message ?? String(err);
|
|
20495
20563
|
this.adapterState.set(id, { status: "retrying", retryCount: 0, lastError: message });
|
|
20496
|
-
this.scheduleAdapterRetry(id
|
|
20564
|
+
this.scheduleAdapterRetry(id);
|
|
20497
20565
|
}
|
|
20498
20566
|
}
|
|
20499
20567
|
this.classicChannels?.configureAdapters(this.fleetConfig?.channels ?? (this.fleetConfig?.channel ? [this.fleetConfig.channel] : []));
|