@standardagents/builder 0.30.1 → 0.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/built-in-routes.js +52 -3
- package/dist/built-in-routes.js.map +1 -1
- package/dist/client/{ApiKeysView-jhfg43UH.js → ApiKeysView-wfApkZad.js} +1 -1
- package/dist/client/CenteredContentView-JFIi6iAA.js +1 -0
- package/dist/client/{CompositionView-DhkLWmtE.js → CompositionView-CIm8Kt1I.js} +1 -1
- package/dist/client/{ConfirmDialog.vue_vue_type_script_setup_true_lang-D-WToRMy.js → ConfirmDialog.vue_vue_type_script_setup_true_lang-DO1fUxUR.js} +1 -1
- package/dist/client/{CopyButton.vue_vue_type_script_setup_true_lang-Dhq0t0dd.js → CopyButton.vue_vue_type_script_setup_true_lang-DfEFB4ze.js} +1 -1
- package/dist/client/{DataTable.vue_vue_type_script_setup_true_lang-D1MDCns-.js → DataTable.vue_vue_type_script_setup_true_lang-4XH4cxYM.js} +1 -1
- package/dist/client/{JsonViewer-BoHrE76S.js → JsonViewer-md2l5DdY.js} +1 -1
- package/dist/client/{LoginView-BpR2nMNf.js → LoginView-BJSfZpgw.js} +1 -1
- package/dist/client/{MarketplaceView-uUf1JYla.js → MarketplaceView-DXE7ys3s.js} +1 -1
- package/dist/client/{Modal.vue_vue_type_script_setup_true_lang-D-SDVFQI.js → Modal.vue_vue_type_script_setup_true_lang-FiL__HMg.js} +1 -1
- package/dist/client/{ModelModal.vue_vue_type_script_setup_true_lang-DE57Zr0r.js → ModelModal.vue_vue_type_script_setup_true_lang-BIBHjNB0.js} +1 -1
- package/dist/client/{ModelsView-CuM_OieH.js → ModelsView-BhtR_WPG.js} +1 -1
- package/dist/client/{PromptEditView-BWjrA2zr.js → PromptEditView-DadQ9eJ0.js} +1 -1
- package/dist/client/{PromptModal-BFxhuG0Z.js → PromptModal-BMBKSmJC.js} +1 -1
- package/dist/client/{PromptsView-AlGsRB6k.js → PromptsView-F1l2HocI.js} +1 -1
- package/dist/client/{ProvidersView-CbXBs3SH.js → ProvidersView-DFWGCJwN.js} +1 -1
- package/dist/client/ThreadInspectorPane.vue_vue_type_script_setup_true_lang-C7JV15r3.js +22 -0
- package/dist/client/{ThreadsView-rN9rzJi1.js → ThreadsView-CMb05n9d.js} +1 -1
- package/dist/client/{ToolsView-0Gpo_RFg.js → ToolsView-7F2ybb1x.js} +1 -1
- package/dist/client/{UiCodeBlock.vue_vue_type_script_setup_true_lang-CNncALQo.js → UiCodeBlock.vue_vue_type_script_setup_true_lang-QytRm7Ql.js} +1 -1
- package/dist/client/{UsersView-iXPbcguY.js → UsersView-Badppc4K.js} +1 -1
- package/dist/client/{VariablesView-C9BB9h34.js → VariablesView-E45rU9bc.js} +1 -1
- package/dist/client/assets/ThreadInspectorPane-Bha1aVZZ.css +1 -0
- package/dist/client/assets/index-C4KCxdCv.css +1 -0
- package/dist/client/{check-BdJVlUmI.js → check-pGlck8qX.js} +1 -1
- package/dist/client/{chevron-right-D49O3XLU.js → chevron-right-FpPE1Obh.js} +1 -1
- package/dist/client/{copy-40uDyTgY.js → copy-Dt1FLh3s.js} +1 -1
- package/dist/client/{formkit-Bl-sERnF.js → formkit-DcZQH9-p.js} +1 -1
- package/dist/client/{index-BCoE48be.js → index-BYdncvi0.js} +3 -3
- package/dist/client/index.html +4 -4
- package/dist/client/{package-1UgoERpx.js → package-DSNwOrcN.js} +1 -1
- package/dist/client/{plus-BzCjfYs0.js → plus-D0GkkdA7.js} +1 -1
- package/dist/client/{timeAgo-cFwldMu-.js → timeAgo-X3Xeq5Kz.js} +1 -1
- package/dist/client/{useActionFeedback-BVifffYQ.js → useActionFeedback-Dxh_Xp0q.js} +1 -1
- package/dist/client/vue-KXHVRwln.js +1 -0
- package/dist/{index-CcnGEkPh.d.ts → index-CL7q3PuW.d.ts} +24 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +159 -16
- package/dist/index.js.map +1 -1
- package/dist/plugin.js +4 -0
- package/dist/plugin.js.map +1 -1
- package/dist/runtime.d.ts +45 -2
- package/dist/runtime.js +155 -16
- package/dist/runtime.js.map +1 -1
- package/dist/test.d.ts +1 -1
- package/package.json +5 -5
- package/dist/client/CenteredContentView-CS0mV2EJ.js +0 -1
- package/dist/client/ThreadInspectorPane.vue_vue_type_script_setup_true_lang-Dm3d37hz.js +0 -22
- package/dist/client/assets/ThreadInspectorPane-CfpdDnUQ.css +0 -1
- package/dist/client/assets/index-BTPsPULO.css +0 -1
- package/dist/client/vue-CmmJuziT.js +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ModelDefinition, AgentDefinition } from './runtime.js';
|
|
2
2
|
export { AgentBuilderEnv, AuthContext, AuthUser, BroadcastOptions, CodeExecutionBridge, DurableAgentBuilder, DurableThread, DurableUserHub, FlowStateSdk, FlowStateWithSdk, HubClientInfo, ImageContextConfig, InjectMessageOptions, LLMProviderInterface, NamespaceResolutionError, PromptContent, PromptDefinition, PromptIncludePart, PromptPart, PromptToolConfig, Provider, ProviderContentPart, ProviderFilePart, ProviderImagePart, ProviderRegistry, ProviderTextPart, SessionToolBinding, SessionToolConfig, SideConfig, SubagentToolConfig, SubpromptConfig, ThreadRegistryEntry, ThreadWatchdog, ThreadWatchdogState, ToolConfig, UpdateThreadParams, User, WatchdogCheckin, WatchdogProbeResult, authenticate, buildImageDescription, cat, createNamespaceContext, emitThreadEvent, enhanceFlowState, exists, find, forceTurn, generateImageDescription, getFileStats, getMessages, getMessagesToSummarize, getShortName, getThumbnail, getUnsummarizedImageAttachments, getVisibleAgentNames, getVisibleModelNames, getVisiblePromptNames, getVisibleToolNames, grep, hasImageAttachments, head, injectMessage, isQualifiedName, linkFile, mkdir, move, optimizeImageContext, parseQualifiedName, qualifyName, queueTool, readFile, readdir, reloadHistory, rename, replaceImagesWithDescriptions, requireAdmin, requireAuth, resolveAgent, resolveHook, resolveModel, resolvePrompt, resolveTool, rmdir, stat, tail, unlink, updateThread, writeFile, writeImage } from './runtime.js';
|
|
3
3
|
export { AgentPluginOptions, agentbuilder, builder } from './plugin.js';
|
|
4
|
-
export { A as Agent, x as AttachmentRef, f as BuilderThreadEndpointHandler, C as CLIENT_STREAM_CHUNK_BYTES, o as ClientDuplex, p as ClientForwarding, m as ClientStreamRequest, n as ClientStreamResponse, k as ClientToolRequest, l as ClientToolResponse, B as Controller, a as ControllerContext, E as Env, w as FileRecord, y as FileStats, u as FlowResult, F as FlowState, G as GrepResult, D as ImageContentPart, I as ImageMetadata, L as LLMResponse, M as Message, J as MessageContent, H as MultimodalContent, R as RequestContext, S as StorageBackend, v as TelemetryEvent, z as TextContentPart, b as ThreadEndpointContext, e as ThreadEnv, q as ThreadInstance, r as ThreadMetadata, T as ToolCall, t as ToolResult, g as callClient, h as callClientStream, c as createThreadEndpointHandler, j as decodeStreamChunk, d as defineController, i as encodeStreamChunk, s as supportsClientForwarding } from './index-
|
|
4
|
+
export { A as Agent, x as AttachmentRef, f as BuilderThreadEndpointHandler, C as CLIENT_STREAM_CHUNK_BYTES, o as ClientDuplex, p as ClientForwarding, m as ClientStreamRequest, n as ClientStreamResponse, k as ClientToolRequest, l as ClientToolResponse, B as Controller, a as ControllerContext, E as Env, w as FileRecord, y as FileStats, u as FlowResult, F as FlowState, G as GrepResult, D as ImageContentPart, I as ImageMetadata, L as LLMResponse, M as Message, J as MessageContent, H as MultimodalContent, R as RequestContext, S as StorageBackend, v as TelemetryEvent, z as TextContentPart, b as ThreadEndpointContext, e as ThreadEnv, q as ThreadInstance, r as ThreadMetadata, T as ToolCall, t as ToolResult, g as callClient, h as callClientStream, c as createThreadEndpointHandler, j as decodeStreamChunk, d as defineController, i as encodeStreamChunk, s as supportsClientForwarding } from './index-CL7q3PuW.js';
|
|
5
5
|
export { AgentType, DefinitionLoader, GlobalNamespaceContext, HookSignatures, ImageContent, ModelCapabilities, ModelProvider, NamespaceContext, PackageSignature, PackedExports, PackedMeta, PackedMetadata, PackedNamespaceContext, PromptInput, PromptTextPart, ProviderAssistantMessage, ProviderConfigSlot, ProviderConfigSlots, ProviderConfigValueSource, ProviderDefinition, ProviderError, ProviderErrorCode, ProviderFactory, ProviderFactoryConfig, ProviderFinishReason, ProviderGeneratedImage, ProviderMessage, ProviderMessageContent, ProviderMethodOverrides, ModelCapabilities as ProviderModelCapabilities, ProviderOverride, ProviderOverrideContext, ProviderReasoningDetail, ProviderRequest, ProviderResponse, ProviderStreamChunk, ProviderSyncOverride, ProviderSystemMessage, ProviderTool, ProviderToolCallPart, ProviderToolMessage, ProviderToolResultContent, ProviderUsage, ProviderUserMessage, ReasoningConfig, StructuredPrompt, TextContent, Tool, ToolArgs, ToolArgsNode, ToolArgsRawShape, ToolContent, belongsToPackage, defineAgent, defineHook, defineModel, definePrompt, defineProvider, defineTool, isPacked, isVisibleInNamespace, mapReasoningLevel, providerConst, providerEnv, providerValue } from '@standardagents/spec';
|
|
6
6
|
export { C as ConstituentItem, D as DiscoveredPackage, N as NamespacedRegistry, P as PackingAnalysis, a as PackingOptions, b as PackingResult, c as UnpackOptions, d as UnpackResult } from './types-Bpe7IANZ.js';
|
|
7
7
|
export { D as DiscoveryConfig, P as PackageDiscoveryService, d as discoverPackages } from './discovery-DiMJWisl.js';
|
package/dist/index.js
CHANGED
|
@@ -14891,6 +14891,10 @@ declare module 'virtual:@standardagents/builder' {
|
|
|
14891
14891
|
parent: string | null;
|
|
14892
14892
|
terminated: number | null;
|
|
14893
14893
|
created_at: number;
|
|
14894
|
+
/** Unix seconds of the last message or execution on this thread (or a descendant). */
|
|
14895
|
+
last_activity_at?: number | null;
|
|
14896
|
+
/** True while the thread is executing a flow. */
|
|
14897
|
+
executing?: boolean;
|
|
14894
14898
|
}
|
|
14895
14899
|
|
|
14896
14900
|
export interface UpdateThreadParams {
|
|
@@ -26192,9 +26196,9 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
26192
26196
|
* Each migration is run in order, starting from the current version + 1.
|
|
26193
26197
|
*/
|
|
26194
26198
|
async runMigrations(fromVersion) {
|
|
26195
|
-
for (const
|
|
26196
|
-
if (
|
|
26197
|
-
await
|
|
26199
|
+
for (const migration48 of migrations) {
|
|
26200
|
+
if (migration48.version > fromVersion) {
|
|
26201
|
+
await migration48.up(this.ctx.storage.sql);
|
|
26198
26202
|
}
|
|
26199
26203
|
}
|
|
26200
26204
|
}
|
|
@@ -29588,6 +29592,25 @@ ${resultContent}${attachmentSummary}`;
|
|
|
29588
29592
|
if (!namespace || typeof namespace.idFromName !== "function") return null;
|
|
29589
29593
|
return namespace.get(namespace.idFromName(threadId));
|
|
29590
29594
|
}
|
|
29595
|
+
/**
|
|
29596
|
+
* Stamp thread activity on the registry so thread lists can sort by recency
|
|
29597
|
+
* of real work and show which threads are executing right now. Registry
|
|
29598
|
+
* bookkeeping is presentation state: a failure here must never take down the
|
|
29599
|
+
* turn that triggered it.
|
|
29600
|
+
*/
|
|
29601
|
+
async recordRegistryActivity(threadId, executing) {
|
|
29602
|
+
try {
|
|
29603
|
+
const namespace = this.env.AGENT_BUILDER;
|
|
29604
|
+
if (!namespace || typeof namespace.idFromName !== "function") return;
|
|
29605
|
+
const agentBuilder = namespace.get(namespace.idFromName("singleton"));
|
|
29606
|
+
await agentBuilder.recordThreadActivity?.(threadId, { executing });
|
|
29607
|
+
} catch (error) {
|
|
29608
|
+
console.error(
|
|
29609
|
+
"[DurableThread] Failed to record thread activity (non-fatal):",
|
|
29610
|
+
error
|
|
29611
|
+
);
|
|
29612
|
+
}
|
|
29613
|
+
}
|
|
29591
29614
|
/** Arm the standing watchdog for an execution start. One pending row max. */
|
|
29592
29615
|
async armExecutionWatchdog(threadId) {
|
|
29593
29616
|
try {
|
|
@@ -29774,6 +29797,7 @@ ${resultContent}${attachmentSummary}`;
|
|
|
29774
29797
|
}
|
|
29775
29798
|
this.isExecuting = false;
|
|
29776
29799
|
this.currentAbortController = null;
|
|
29800
|
+
await this.recordRegistryActivity(threadId, false);
|
|
29777
29801
|
tookOver = true;
|
|
29778
29802
|
} else if (incomplete.length > 0 && silenceMs <= ceiling) {
|
|
29779
29803
|
return report("observing", "none");
|
|
@@ -29977,6 +30001,7 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
29977
30001
|
this.isExecuting = true;
|
|
29978
30002
|
this.currentAbortController = new AbortController();
|
|
29979
30003
|
await this.armExecutionWatchdog(threadId);
|
|
30004
|
+
await this.recordRegistryActivity(threadId, true);
|
|
29980
30005
|
try {
|
|
29981
30006
|
const agentDef = await this.loadAgent(agentName);
|
|
29982
30007
|
const packageId = agentDef.__package?.packageId;
|
|
@@ -30108,6 +30133,7 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
30108
30133
|
this.isExecuting = false;
|
|
30109
30134
|
this.currentAbortController = null;
|
|
30110
30135
|
await this.disarmExecutionWatchdog(threadId);
|
|
30136
|
+
await this.recordRegistryActivity(threadId, false);
|
|
30111
30137
|
}
|
|
30112
30138
|
}
|
|
30113
30139
|
/**
|
|
@@ -30168,6 +30194,7 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
30168
30194
|
this.isExecuting = true;
|
|
30169
30195
|
this.currentAbortController = new AbortController();
|
|
30170
30196
|
await this.armExecutionWatchdog(threadId);
|
|
30197
|
+
await this.recordRegistryActivity(threadId, true);
|
|
30171
30198
|
try {
|
|
30172
30199
|
const agentBuilderId = this.env.AGENT_BUILDER.idFromName("singleton");
|
|
30173
30200
|
const agentBuilder = this.env.AGENT_BUILDER.get(agentBuilderId);
|
|
@@ -30307,6 +30334,7 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
30307
30334
|
this.isExecuting = false;
|
|
30308
30335
|
this.currentAbortController = null;
|
|
30309
30336
|
await this.disarmExecutionWatchdog(threadId);
|
|
30337
|
+
await this.recordRegistryActivity(threadId, false);
|
|
30310
30338
|
}
|
|
30311
30339
|
}
|
|
30312
30340
|
/**
|
|
@@ -30324,6 +30352,7 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
30324
30352
|
this.isExecuting = true;
|
|
30325
30353
|
this.currentAbortController = new AbortController();
|
|
30326
30354
|
await this.armExecutionWatchdog(threadId);
|
|
30355
|
+
await this.recordRegistryActivity(threadId, true);
|
|
30327
30356
|
try {
|
|
30328
30357
|
const agentBuilderId = this.env.AGENT_BUILDER.idFromName("singleton");
|
|
30329
30358
|
const agentBuilder = this.env.AGENT_BUILDER.get(agentBuilderId);
|
|
@@ -30433,6 +30462,7 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
30433
30462
|
this.isExecuting = false;
|
|
30434
30463
|
this.currentAbortController = null;
|
|
30435
30464
|
await this.disarmExecutionWatchdog(threadId);
|
|
30465
|
+
await this.recordRegistryActivity(threadId, false);
|
|
30436
30466
|
const latestQueuedSide = await this.getLatestQueuedMessageSide();
|
|
30437
30467
|
if (latestQueuedSide) {
|
|
30438
30468
|
await this.ensureQueuedMessageExecution(threadId, latestQueuedSide);
|
|
@@ -31526,9 +31556,25 @@ var migration46 = {
|
|
|
31526
31556
|
}
|
|
31527
31557
|
};
|
|
31528
31558
|
|
|
31559
|
+
// src/durable-objects/agentbuilder-migrations/0013_add_thread_activity.ts
|
|
31560
|
+
var migration47 = {
|
|
31561
|
+
version: 13,
|
|
31562
|
+
async up(sql) {
|
|
31563
|
+
sql.exec(`ALTER TABLE threads ADD COLUMN last_activity_at INTEGER`);
|
|
31564
|
+
sql.exec(`ALTER TABLE threads ADD COLUMN executing_since INTEGER`);
|
|
31565
|
+
sql.exec(
|
|
31566
|
+
`CREATE INDEX IF NOT EXISTS idx_threads_last_activity_at ON threads(last_activity_at)`
|
|
31567
|
+
);
|
|
31568
|
+
sql.exec(`UPDATE threads SET last_activity_at = created_at`);
|
|
31569
|
+
sql.exec(`
|
|
31570
|
+
INSERT OR REPLACE INTO _metadata (key, value) VALUES ('schema_version', '13')
|
|
31571
|
+
`);
|
|
31572
|
+
}
|
|
31573
|
+
};
|
|
31574
|
+
|
|
31529
31575
|
// src/durable-objects/agentbuilder-migrations/index.ts
|
|
31530
|
-
var migrations2 = [migration35, migration36, migration37, migration38, migration39, migration40, migration41, migration42, migration43, migration44, migration45, migration46];
|
|
31531
|
-
var LATEST_SCHEMA_VERSION2 =
|
|
31576
|
+
var migrations2 = [migration35, migration36, migration37, migration38, migration39, migration40, migration41, migration42, migration43, migration44, migration45, migration46, migration47];
|
|
31577
|
+
var LATEST_SCHEMA_VERSION2 = 13;
|
|
31532
31578
|
|
|
31533
31579
|
// src/utils/crypto.ts
|
|
31534
31580
|
var CryptoUtil = class {
|
|
@@ -31727,6 +31773,8 @@ function parseStoredPermissions(value) {
|
|
|
31727
31773
|
return null;
|
|
31728
31774
|
}
|
|
31729
31775
|
}
|
|
31776
|
+
var EXECUTING_STALE_AFTER_SECONDS = 15 * 60;
|
|
31777
|
+
var isThreadExecuting = (executingSince, nowSeconds) => executingSince != null && nowSeconds - executingSince < EXECUTING_STALE_AFTER_SECONDS;
|
|
31730
31778
|
var DurableAgentBuilder = class extends DurableObject {
|
|
31731
31779
|
migratedToVersion = null;
|
|
31732
31780
|
eventSockets = /* @__PURE__ */ new Set();
|
|
@@ -32295,9 +32343,9 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
32295
32343
|
}
|
|
32296
32344
|
}
|
|
32297
32345
|
async runMigrations(fromVersion) {
|
|
32298
|
-
for (const
|
|
32299
|
-
if (
|
|
32300
|
-
await
|
|
32346
|
+
for (const migration48 of migrations2) {
|
|
32347
|
+
if (migration48.version > fromVersion) {
|
|
32348
|
+
await migration48.up(this.ctx.storage.sql);
|
|
32301
32349
|
}
|
|
32302
32350
|
}
|
|
32303
32351
|
}
|
|
@@ -32339,8 +32387,8 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
32339
32387
|
const encryptedEnv = await this.encryptEnvRecord(env);
|
|
32340
32388
|
const properties = this.withEnvTypeRecord(params.properties ?? null, envTypes);
|
|
32341
32389
|
await this.ctx.storage.sql.exec(
|
|
32342
|
-
`INSERT INTO threads (id, agent_name, user_id, tags, env, tenvs, properties, parent, terminated, created_at)
|
|
32343
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, NULL, ?)`,
|
|
32390
|
+
`INSERT INTO threads (id, agent_name, user_id, tags, env, tenvs, properties, parent, terminated, created_at, last_activity_at)
|
|
32391
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?)`,
|
|
32344
32392
|
id,
|
|
32345
32393
|
params.agent_name,
|
|
32346
32394
|
params.user_id || null,
|
|
@@ -32349,6 +32397,7 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
32349
32397
|
encryptedEnv,
|
|
32350
32398
|
properties ? JSON.stringify(properties) : null,
|
|
32351
32399
|
params.parent ?? null,
|
|
32400
|
+
now,
|
|
32352
32401
|
now
|
|
32353
32402
|
);
|
|
32354
32403
|
const thread = {
|
|
@@ -32362,7 +32411,9 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
32362
32411
|
properties,
|
|
32363
32412
|
parent: params.parent ?? null,
|
|
32364
32413
|
terminated: null,
|
|
32365
|
-
created_at: now
|
|
32414
|
+
created_at: now,
|
|
32415
|
+
last_activity_at: now,
|
|
32416
|
+
executing: false
|
|
32366
32417
|
};
|
|
32367
32418
|
const eventThread = await this.toThreadEventPayload(thread);
|
|
32368
32419
|
this.broadcastEvent({ type: "thread_created", thread: eventThread });
|
|
@@ -32418,7 +32469,10 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
32418
32469
|
*/
|
|
32419
32470
|
async getThread(id) {
|
|
32420
32471
|
await this.ensureMigrated();
|
|
32421
|
-
const cursor = await this.ctx.storage.sql.exec(
|
|
32472
|
+
const cursor = await this.ctx.storage.sql.exec(
|
|
32473
|
+
`SELECT id, agent_name, user_id, tags, env, tenvs, properties, parent, terminated, created_at, last_activity_at, executing_since FROM threads WHERE id = ?`,
|
|
32474
|
+
id
|
|
32475
|
+
);
|
|
32422
32476
|
const rows = cursor.toArray();
|
|
32423
32477
|
if (rows.length === 0) {
|
|
32424
32478
|
return null;
|
|
@@ -32438,7 +32492,12 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
32438
32492
|
properties,
|
|
32439
32493
|
parent: row.parent,
|
|
32440
32494
|
terminated: row.terminated,
|
|
32441
|
-
created_at: row.created_at
|
|
32495
|
+
created_at: row.created_at,
|
|
32496
|
+
last_activity_at: row.last_activity_at ?? row.created_at,
|
|
32497
|
+
executing: isThreadExecuting(
|
|
32498
|
+
row.executing_since,
|
|
32499
|
+
Math.floor(Date.now() / 1e3)
|
|
32500
|
+
)
|
|
32442
32501
|
};
|
|
32443
32502
|
}
|
|
32444
32503
|
/**
|
|
@@ -32479,6 +32538,7 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
32479
32538
|
*/
|
|
32480
32539
|
async listThreads(params) {
|
|
32481
32540
|
await this.ensureMigrated();
|
|
32541
|
+
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
32482
32542
|
const whereClauses = [];
|
|
32483
32543
|
const args = [];
|
|
32484
32544
|
if (params?.agent_name) {
|
|
@@ -32514,6 +32574,18 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
32514
32574
|
whereClauses.push("created_at <= ?");
|
|
32515
32575
|
args.push(params.endDate);
|
|
32516
32576
|
}
|
|
32577
|
+
if (params?.executing === true) {
|
|
32578
|
+
whereClauses.push("executing_since IS NOT NULL AND executing_since > ?");
|
|
32579
|
+
args.push(nowSeconds - EXECUTING_STALE_AFTER_SECONDS);
|
|
32580
|
+
} else if (params?.executing === false) {
|
|
32581
|
+
whereClauses.push("(executing_since IS NULL OR executing_since <= ?)");
|
|
32582
|
+
args.push(nowSeconds - EXECUTING_STALE_AFTER_SECONDS);
|
|
32583
|
+
}
|
|
32584
|
+
if (params?.terminated === true) {
|
|
32585
|
+
whereClauses.push("terminated IS NOT NULL");
|
|
32586
|
+
} else if (params?.terminated === false) {
|
|
32587
|
+
whereClauses.push("terminated IS NULL");
|
|
32588
|
+
}
|
|
32517
32589
|
const whereClause = whereClauses.length > 0 ? `WHERE ${whereClauses.join(" AND ")}` : "";
|
|
32518
32590
|
const countCursor = await this.ctx.storage.sql.exec(
|
|
32519
32591
|
`SELECT COUNT(*) as count FROM threads ${whereClause}`,
|
|
@@ -32522,10 +32594,11 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
32522
32594
|
const total = countCursor.one().count;
|
|
32523
32595
|
const limit = params?.limit ?? 100;
|
|
32524
32596
|
const offset = params?.offset ?? 0;
|
|
32597
|
+
const orderByClause = params?.sort === "created" ? "created_at DESC" : params?.sort === "oldest" ? "created_at ASC" : "COALESCE(last_activity_at, created_at) DESC, created_at DESC";
|
|
32525
32598
|
const cursor = await this.ctx.storage.sql.exec(
|
|
32526
|
-
`SELECT id, agent_name, user_id, tags, properties, parent, terminated, created_at FROM threads
|
|
32599
|
+
`SELECT id, agent_name, user_id, tags, properties, parent, terminated, created_at, last_activity_at, executing_since FROM threads
|
|
32527
32600
|
${whereClause}
|
|
32528
|
-
ORDER BY
|
|
32601
|
+
ORDER BY ${orderByClause}
|
|
32529
32602
|
LIMIT ? OFFSET ?`,
|
|
32530
32603
|
...args,
|
|
32531
32604
|
limit,
|
|
@@ -32545,10 +32618,80 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
32545
32618
|
properties: row.properties ? JSON.parse(row.properties) : null,
|
|
32546
32619
|
parent: row.parent,
|
|
32547
32620
|
terminated: row.terminated,
|
|
32548
|
-
created_at: row.created_at
|
|
32621
|
+
created_at: row.created_at,
|
|
32622
|
+
last_activity_at: row.last_activity_at ?? row.created_at,
|
|
32623
|
+
executing: isThreadExecuting(row.executing_since, nowSeconds)
|
|
32549
32624
|
}));
|
|
32550
32625
|
return { threads, total };
|
|
32551
32626
|
}
|
|
32627
|
+
/**
|
|
32628
|
+
* Distinct owners of threads visible to the caller, with counts, so a thread
|
|
32629
|
+
* list can offer an "owner" filter without exposing the admin-only user
|
|
32630
|
+
* directory (which is unavailable on hosted instances).
|
|
32631
|
+
*/
|
|
32632
|
+
async listThreadOwners(params) {
|
|
32633
|
+
await this.ensureMigrated();
|
|
32634
|
+
const whereClause = params?.user_id ? "WHERE t.user_id = ?" : "";
|
|
32635
|
+
const args = params?.user_id ? [params.user_id] : [];
|
|
32636
|
+
const cursor = await this.ctx.storage.sql.exec(
|
|
32637
|
+
`SELECT t.user_id AS user_id,
|
|
32638
|
+
u.username AS username,
|
|
32639
|
+
u.display_name AS display_name,
|
|
32640
|
+
u.email AS email,
|
|
32641
|
+
COUNT(*) AS thread_count
|
|
32642
|
+
FROM threads t
|
|
32643
|
+
LEFT JOIN users u ON u.id = t.user_id
|
|
32644
|
+
${whereClause}
|
|
32645
|
+
GROUP BY t.user_id
|
|
32646
|
+
ORDER BY thread_count DESC`,
|
|
32647
|
+
...args
|
|
32648
|
+
);
|
|
32649
|
+
return cursor.toArray();
|
|
32650
|
+
}
|
|
32651
|
+
/**
|
|
32652
|
+
* Record that a thread did work: stamp `last_activity_at` and flip the
|
|
32653
|
+
* executing marker. Activity bubbles up the parent chain so a root thread
|
|
32654
|
+
* sorts by the freshest work anywhere in its subagent tree — otherwise a
|
|
32655
|
+
* long-running subagent would let its parent sink down an activity-sorted
|
|
32656
|
+
* list.
|
|
32657
|
+
*/
|
|
32658
|
+
async recordThreadActivity(threadId, options) {
|
|
32659
|
+
await this.ensureMigrated();
|
|
32660
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
32661
|
+
const executing = options?.executing;
|
|
32662
|
+
await this.ctx.storage.sql.exec(
|
|
32663
|
+
`UPDATE threads
|
|
32664
|
+
SET last_activity_at = ?
|
|
32665
|
+
WHERE id IN (
|
|
32666
|
+
WITH RECURSIVE ancestry(id, parent) AS (
|
|
32667
|
+
SELECT id, parent FROM threads WHERE id = ?
|
|
32668
|
+
UNION ALL
|
|
32669
|
+
SELECT t.id, t.parent FROM threads t JOIN ancestry a ON t.id = a.parent
|
|
32670
|
+
)
|
|
32671
|
+
SELECT id FROM ancestry
|
|
32672
|
+
)`,
|
|
32673
|
+
now,
|
|
32674
|
+
threadId
|
|
32675
|
+
);
|
|
32676
|
+
if (executing === true) {
|
|
32677
|
+
await this.ctx.storage.sql.exec(
|
|
32678
|
+
`UPDATE threads SET executing_since = ? WHERE id = ? AND executing_since IS NULL`,
|
|
32679
|
+
now,
|
|
32680
|
+
threadId
|
|
32681
|
+
);
|
|
32682
|
+
} else if (executing === false) {
|
|
32683
|
+
await this.ctx.storage.sql.exec(
|
|
32684
|
+
`UPDATE threads SET executing_since = NULL WHERE id = ?`,
|
|
32685
|
+
threadId
|
|
32686
|
+
);
|
|
32687
|
+
}
|
|
32688
|
+
this.broadcastEvent({
|
|
32689
|
+
type: "thread_activity",
|
|
32690
|
+
threadId,
|
|
32691
|
+
last_activity_at: now,
|
|
32692
|
+
executing: executing === true
|
|
32693
|
+
});
|
|
32694
|
+
}
|
|
32552
32695
|
/**
|
|
32553
32696
|
* Delete a thread from the registry.
|
|
32554
32697
|
*/
|