@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/runtime.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { e as ThreadEnv, A as Agent, r as ThreadMetadata, t as ToolResult, M as Message, k as ClientToolRequest, l as ClientToolResponse, m as ClientStreamRequest, n as ClientStreamResponse, w as FileRecord, F as FlowState, y as FileStats, G as GrepResult, x as AttachmentRef, J as MessageContent, E as Env, q as ThreadInstance } from './index-
|
|
2
|
-
export { f as BuilderThreadEndpointHandler, C as CLIENT_STREAM_CHUNK_BYTES, o as ClientDuplex, p as ClientForwarding, B as Controller, a as ControllerContext, u as FlowResult, D as ImageContentPart, I as ImageMetadata, L as LLMResponse, H as MultimodalContent, R as RequestContext, S as StorageBackend, v as TelemetryEvent, z as TextContentPart, b as ThreadEndpointContext, T as ToolCall, g as callClient, h as callClientStream, c as createThreadEndpointHandler, j as decodeStreamChunk, d as defineController, i as encodeStreamChunk, s as supportsClientForwarding } from './index-
|
|
1
|
+
import { e as ThreadEnv, A as Agent, r as ThreadMetadata, t as ToolResult, M as Message, k as ClientToolRequest, l as ClientToolResponse, m as ClientStreamRequest, n as ClientStreamResponse, w as FileRecord, F as FlowState, y as FileStats, G as GrepResult, x as AttachmentRef, J as MessageContent, E as Env, q as ThreadInstance } from './index-CL7q3PuW.js';
|
|
2
|
+
export { f as BuilderThreadEndpointHandler, C as CLIENT_STREAM_CHUNK_BYTES, o as ClientDuplex, p as ClientForwarding, B as Controller, a as ControllerContext, u as FlowResult, D as ImageContentPart, I as ImageMetadata, L as LLMResponse, H as MultimodalContent, R as RequestContext, S as StorageBackend, v as TelemetryEvent, z as TextContentPart, b as ThreadEndpointContext, T as ToolCall, 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';
|
|
3
3
|
import { CodeExecutionOptions, CodeExecutionResult, SubagentRegistryEntry, InjectMessageInput, QueueMessageInput, CredentialGrant, SkillMetadata, SkillFileInput, ModelDefinition as ModelDefinition$1, ToolArgs, PromptTextPart, PromptEnvPart, VariableDefinition, SubpromptConfig as SubpromptConfig$1, PromptToolConfig as PromptToolConfig$1, SubagentToolConfig as SubagentToolConfig$1, ReasoningConfig, SideConfig as SideConfig$1, LLMProviderInterface, ContentPart, TextPart, ImagePart, FilePart, ThreadState, NamespaceContext, DefinitionLoader } from '@standardagents/spec';
|
|
4
4
|
export { AgentType, DefinitionLoader, GlobalNamespaceContext, HookSignatures, ImageContent, ModelCapabilities, ModelProvider, NamespaceContext, PackageSignature, PackedExports, PackedMeta, PackedMetadata, PackedNamespaceContext, PromptInput, PromptTextPart, ProviderAssistantMessage, ProviderError, ProviderErrorCode, ProviderFactory, ProviderFactoryConfig, ProviderFinishReason, ProviderGeneratedImage, ProviderMessage, ProviderMessageContent, ModelCapabilities as ProviderModelCapabilities, ProviderReasoningDetail, ProviderRequest, ProviderResponse, ProviderStreamChunk, ProviderSystemMessage, ProviderTool, ProviderToolCallPart, ProviderToolMessage, ProviderToolResultContent, ProviderUsage, ProviderUserMessage, ReasoningConfig, StructuredPrompt, TextContent, Tool, ToolArgs, ToolArgsNode, ToolArgsRawShape, ToolContent, belongsToPackage, defineAgent, defineHook, defineModel, definePrompt, defineTool, isPacked, isVisibleInNamespace, mapReasoningLevel } from '@standardagents/spec';
|
|
5
5
|
import { DurableObject, WorkerEntrypoint } from 'cloudflare:workers';
|
|
@@ -1241,6 +1241,13 @@ declare class DurableThread<Env extends ThreadEnv = ThreadEnv> extends DurableOb
|
|
|
1241
1241
|
* Returns null on deployments whose generated config predates the binding.
|
|
1242
1242
|
*/
|
|
1243
1243
|
private watchdogCompanion;
|
|
1244
|
+
/**
|
|
1245
|
+
* Stamp thread activity on the registry so thread lists can sort by recency
|
|
1246
|
+
* of real work and show which threads are executing right now. Registry
|
|
1247
|
+
* bookkeeping is presentation state: a failure here must never take down the
|
|
1248
|
+
* turn that triggered it.
|
|
1249
|
+
*/
|
|
1250
|
+
private recordRegistryActivity;
|
|
1244
1251
|
/** Arm the standing watchdog for an execution start. One pending row max. */
|
|
1245
1252
|
private armExecutionWatchdog;
|
|
1246
1253
|
/** Disarm on clean execution end. Completed check rows are noise, not history. */
|
|
@@ -1802,6 +1809,10 @@ interface ThreadRegistryEntry {
|
|
|
1802
1809
|
parent: string | null;
|
|
1803
1810
|
terminated: number | null;
|
|
1804
1811
|
created_at: number;
|
|
1812
|
+
/** Unix seconds of the last message or execution on this thread (or a descendant). */
|
|
1813
|
+
last_activity_at?: number | null;
|
|
1814
|
+
/** True while the thread is executing a flow (stale markers read as false). */
|
|
1815
|
+
executing?: boolean;
|
|
1805
1816
|
}
|
|
1806
1817
|
interface PendingSubagentAttachmentRef {
|
|
1807
1818
|
path: string;
|
|
@@ -1910,6 +1921,8 @@ interface Provider$1 {
|
|
|
1910
1921
|
sdk: string;
|
|
1911
1922
|
api_key: string;
|
|
1912
1923
|
}
|
|
1924
|
+
/** Sort orders supported by `listThreads`. */
|
|
1925
|
+
type ThreadListSort = 'activity' | 'created' | 'oldest';
|
|
1913
1926
|
declare class DurableAgentBuilder<Env extends AgentBuilderEnv = AgentBuilderEnv> extends DurableObject<Env> {
|
|
1914
1927
|
private migratedToVersion;
|
|
1915
1928
|
private eventSockets;
|
|
@@ -2024,10 +2037,40 @@ declare class DurableAgentBuilder<Env extends AgentBuilderEnv = AgentBuilderEnv>
|
|
|
2024
2037
|
limit?: number;
|
|
2025
2038
|
offset?: number;
|
|
2026
2039
|
include_children?: boolean;
|
|
2040
|
+
/** Default `activity`: most recently worked-on threads first. */
|
|
2041
|
+
sort?: ThreadListSort;
|
|
2042
|
+
/** `true` → only threads currently executing; `false` → only idle ones. */
|
|
2043
|
+
executing?: boolean;
|
|
2044
|
+
/** `false` hides terminated threads; `true` shows only terminated ones. */
|
|
2045
|
+
terminated?: boolean;
|
|
2027
2046
|
}): Promise<{
|
|
2028
2047
|
threads: ThreadRegistryEntry[];
|
|
2029
2048
|
total: number;
|
|
2030
2049
|
}>;
|
|
2050
|
+
/**
|
|
2051
|
+
* Distinct owners of threads visible to the caller, with counts, so a thread
|
|
2052
|
+
* list can offer an "owner" filter without exposing the admin-only user
|
|
2053
|
+
* directory (which is unavailable on hosted instances).
|
|
2054
|
+
*/
|
|
2055
|
+
listThreadOwners(params?: {
|
|
2056
|
+
user_id?: string;
|
|
2057
|
+
}): Promise<Array<{
|
|
2058
|
+
user_id: string | null;
|
|
2059
|
+
username: string | null;
|
|
2060
|
+
display_name: string | null;
|
|
2061
|
+
email: string | null;
|
|
2062
|
+
thread_count: number;
|
|
2063
|
+
}>>;
|
|
2064
|
+
/**
|
|
2065
|
+
* Record that a thread did work: stamp `last_activity_at` and flip the
|
|
2066
|
+
* executing marker. Activity bubbles up the parent chain so a root thread
|
|
2067
|
+
* sorts by the freshest work anywhere in its subagent tree — otherwise a
|
|
2068
|
+
* long-running subagent would let its parent sink down an activity-sorted
|
|
2069
|
+
* list.
|
|
2070
|
+
*/
|
|
2071
|
+
recordThreadActivity(threadId: string, options?: {
|
|
2072
|
+
executing?: boolean;
|
|
2073
|
+
}): Promise<void>;
|
|
2031
2074
|
/**
|
|
2032
2075
|
* Delete a thread from the registry.
|
|
2033
2076
|
*/
|
package/dist/runtime.js
CHANGED
|
@@ -17790,9 +17790,9 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
17790
17790
|
* Each migration is run in order, starting from the current version + 1.
|
|
17791
17791
|
*/
|
|
17792
17792
|
async runMigrations(fromVersion) {
|
|
17793
|
-
for (const
|
|
17794
|
-
if (
|
|
17795
|
-
await
|
|
17793
|
+
for (const migration48 of migrations) {
|
|
17794
|
+
if (migration48.version > fromVersion) {
|
|
17795
|
+
await migration48.up(this.ctx.storage.sql);
|
|
17796
17796
|
}
|
|
17797
17797
|
}
|
|
17798
17798
|
}
|
|
@@ -21186,6 +21186,25 @@ ${resultContent}${attachmentSummary}`;
|
|
|
21186
21186
|
if (!namespace || typeof namespace.idFromName !== "function") return null;
|
|
21187
21187
|
return namespace.get(namespace.idFromName(threadId));
|
|
21188
21188
|
}
|
|
21189
|
+
/**
|
|
21190
|
+
* Stamp thread activity on the registry so thread lists can sort by recency
|
|
21191
|
+
* of real work and show which threads are executing right now. Registry
|
|
21192
|
+
* bookkeeping is presentation state: a failure here must never take down the
|
|
21193
|
+
* turn that triggered it.
|
|
21194
|
+
*/
|
|
21195
|
+
async recordRegistryActivity(threadId, executing) {
|
|
21196
|
+
try {
|
|
21197
|
+
const namespace = this.env.AGENT_BUILDER;
|
|
21198
|
+
if (!namespace || typeof namespace.idFromName !== "function") return;
|
|
21199
|
+
const agentBuilder = namespace.get(namespace.idFromName("singleton"));
|
|
21200
|
+
await agentBuilder.recordThreadActivity?.(threadId, { executing });
|
|
21201
|
+
} catch (error) {
|
|
21202
|
+
console.error(
|
|
21203
|
+
"[DurableThread] Failed to record thread activity (non-fatal):",
|
|
21204
|
+
error
|
|
21205
|
+
);
|
|
21206
|
+
}
|
|
21207
|
+
}
|
|
21189
21208
|
/** Arm the standing watchdog for an execution start. One pending row max. */
|
|
21190
21209
|
async armExecutionWatchdog(threadId) {
|
|
21191
21210
|
try {
|
|
@@ -21372,6 +21391,7 @@ ${resultContent}${attachmentSummary}`;
|
|
|
21372
21391
|
}
|
|
21373
21392
|
this.isExecuting = false;
|
|
21374
21393
|
this.currentAbortController = null;
|
|
21394
|
+
await this.recordRegistryActivity(threadId, false);
|
|
21375
21395
|
tookOver = true;
|
|
21376
21396
|
} else if (incomplete.length > 0 && silenceMs <= ceiling) {
|
|
21377
21397
|
return report("observing", "none");
|
|
@@ -21575,6 +21595,7 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
21575
21595
|
this.isExecuting = true;
|
|
21576
21596
|
this.currentAbortController = new AbortController();
|
|
21577
21597
|
await this.armExecutionWatchdog(threadId);
|
|
21598
|
+
await this.recordRegistryActivity(threadId, true);
|
|
21578
21599
|
try {
|
|
21579
21600
|
const agentDef = await this.loadAgent(agentName);
|
|
21580
21601
|
const packageId = agentDef.__package?.packageId;
|
|
@@ -21706,6 +21727,7 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
21706
21727
|
this.isExecuting = false;
|
|
21707
21728
|
this.currentAbortController = null;
|
|
21708
21729
|
await this.disarmExecutionWatchdog(threadId);
|
|
21730
|
+
await this.recordRegistryActivity(threadId, false);
|
|
21709
21731
|
}
|
|
21710
21732
|
}
|
|
21711
21733
|
/**
|
|
@@ -21766,6 +21788,7 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
21766
21788
|
this.isExecuting = true;
|
|
21767
21789
|
this.currentAbortController = new AbortController();
|
|
21768
21790
|
await this.armExecutionWatchdog(threadId);
|
|
21791
|
+
await this.recordRegistryActivity(threadId, true);
|
|
21769
21792
|
try {
|
|
21770
21793
|
const agentBuilderId = this.env.AGENT_BUILDER.idFromName("singleton");
|
|
21771
21794
|
const agentBuilder = this.env.AGENT_BUILDER.get(agentBuilderId);
|
|
@@ -21905,6 +21928,7 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
21905
21928
|
this.isExecuting = false;
|
|
21906
21929
|
this.currentAbortController = null;
|
|
21907
21930
|
await this.disarmExecutionWatchdog(threadId);
|
|
21931
|
+
await this.recordRegistryActivity(threadId, false);
|
|
21908
21932
|
}
|
|
21909
21933
|
}
|
|
21910
21934
|
/**
|
|
@@ -21922,6 +21946,7 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
21922
21946
|
this.isExecuting = true;
|
|
21923
21947
|
this.currentAbortController = new AbortController();
|
|
21924
21948
|
await this.armExecutionWatchdog(threadId);
|
|
21949
|
+
await this.recordRegistryActivity(threadId, true);
|
|
21925
21950
|
try {
|
|
21926
21951
|
const agentBuilderId = this.env.AGENT_BUILDER.idFromName("singleton");
|
|
21927
21952
|
const agentBuilder = this.env.AGENT_BUILDER.get(agentBuilderId);
|
|
@@ -22031,6 +22056,7 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
22031
22056
|
this.isExecuting = false;
|
|
22032
22057
|
this.currentAbortController = null;
|
|
22033
22058
|
await this.disarmExecutionWatchdog(threadId);
|
|
22059
|
+
await this.recordRegistryActivity(threadId, false);
|
|
22034
22060
|
const latestQueuedSide = await this.getLatestQueuedMessageSide();
|
|
22035
22061
|
if (latestQueuedSide) {
|
|
22036
22062
|
await this.ensureQueuedMessageExecution(threadId, latestQueuedSide);
|
|
@@ -23124,9 +23150,25 @@ var migration46 = {
|
|
|
23124
23150
|
}
|
|
23125
23151
|
};
|
|
23126
23152
|
|
|
23153
|
+
// src/durable-objects/agentbuilder-migrations/0013_add_thread_activity.ts
|
|
23154
|
+
var migration47 = {
|
|
23155
|
+
version: 13,
|
|
23156
|
+
async up(sql) {
|
|
23157
|
+
sql.exec(`ALTER TABLE threads ADD COLUMN last_activity_at INTEGER`);
|
|
23158
|
+
sql.exec(`ALTER TABLE threads ADD COLUMN executing_since INTEGER`);
|
|
23159
|
+
sql.exec(
|
|
23160
|
+
`CREATE INDEX IF NOT EXISTS idx_threads_last_activity_at ON threads(last_activity_at)`
|
|
23161
|
+
);
|
|
23162
|
+
sql.exec(`UPDATE threads SET last_activity_at = created_at`);
|
|
23163
|
+
sql.exec(`
|
|
23164
|
+
INSERT OR REPLACE INTO _metadata (key, value) VALUES ('schema_version', '13')
|
|
23165
|
+
`);
|
|
23166
|
+
}
|
|
23167
|
+
};
|
|
23168
|
+
|
|
23127
23169
|
// src/durable-objects/agentbuilder-migrations/index.ts
|
|
23128
|
-
var migrations2 = [migration35, migration36, migration37, migration38, migration39, migration40, migration41, migration42, migration43, migration44, migration45, migration46];
|
|
23129
|
-
var LATEST_SCHEMA_VERSION2 =
|
|
23170
|
+
var migrations2 = [migration35, migration36, migration37, migration38, migration39, migration40, migration41, migration42, migration43, migration44, migration45, migration46, migration47];
|
|
23171
|
+
var LATEST_SCHEMA_VERSION2 = 13;
|
|
23130
23172
|
|
|
23131
23173
|
// src/utils/crypto.ts
|
|
23132
23174
|
var CryptoUtil = class {
|
|
@@ -23325,6 +23367,8 @@ function parseStoredPermissions(value) {
|
|
|
23325
23367
|
return null;
|
|
23326
23368
|
}
|
|
23327
23369
|
}
|
|
23370
|
+
var EXECUTING_STALE_AFTER_SECONDS = 15 * 60;
|
|
23371
|
+
var isThreadExecuting = (executingSince, nowSeconds) => executingSince != null && nowSeconds - executingSince < EXECUTING_STALE_AFTER_SECONDS;
|
|
23328
23372
|
var DurableAgentBuilder = class extends DurableObject {
|
|
23329
23373
|
migratedToVersion = null;
|
|
23330
23374
|
eventSockets = /* @__PURE__ */ new Set();
|
|
@@ -23893,9 +23937,9 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
23893
23937
|
}
|
|
23894
23938
|
}
|
|
23895
23939
|
async runMigrations(fromVersion) {
|
|
23896
|
-
for (const
|
|
23897
|
-
if (
|
|
23898
|
-
await
|
|
23940
|
+
for (const migration48 of migrations2) {
|
|
23941
|
+
if (migration48.version > fromVersion) {
|
|
23942
|
+
await migration48.up(this.ctx.storage.sql);
|
|
23899
23943
|
}
|
|
23900
23944
|
}
|
|
23901
23945
|
}
|
|
@@ -23937,8 +23981,8 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
23937
23981
|
const encryptedEnv = await this.encryptEnvRecord(env);
|
|
23938
23982
|
const properties = this.withEnvTypeRecord(params.properties ?? null, envTypes);
|
|
23939
23983
|
await this.ctx.storage.sql.exec(
|
|
23940
|
-
`INSERT INTO threads (id, agent_name, user_id, tags, env, tenvs, properties, parent, terminated, created_at)
|
|
23941
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, NULL, ?)`,
|
|
23984
|
+
`INSERT INTO threads (id, agent_name, user_id, tags, env, tenvs, properties, parent, terminated, created_at, last_activity_at)
|
|
23985
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?)`,
|
|
23942
23986
|
id,
|
|
23943
23987
|
params.agent_name,
|
|
23944
23988
|
params.user_id || null,
|
|
@@ -23947,6 +23991,7 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
23947
23991
|
encryptedEnv,
|
|
23948
23992
|
properties ? JSON.stringify(properties) : null,
|
|
23949
23993
|
params.parent ?? null,
|
|
23994
|
+
now,
|
|
23950
23995
|
now
|
|
23951
23996
|
);
|
|
23952
23997
|
const thread = {
|
|
@@ -23960,7 +24005,9 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
23960
24005
|
properties,
|
|
23961
24006
|
parent: params.parent ?? null,
|
|
23962
24007
|
terminated: null,
|
|
23963
|
-
created_at: now
|
|
24008
|
+
created_at: now,
|
|
24009
|
+
last_activity_at: now,
|
|
24010
|
+
executing: false
|
|
23964
24011
|
};
|
|
23965
24012
|
const eventThread = await this.toThreadEventPayload(thread);
|
|
23966
24013
|
this.broadcastEvent({ type: "thread_created", thread: eventThread });
|
|
@@ -24016,7 +24063,10 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
24016
24063
|
*/
|
|
24017
24064
|
async getThread(id) {
|
|
24018
24065
|
await this.ensureMigrated();
|
|
24019
|
-
const cursor = await this.ctx.storage.sql.exec(
|
|
24066
|
+
const cursor = await this.ctx.storage.sql.exec(
|
|
24067
|
+
`SELECT id, agent_name, user_id, tags, env, tenvs, properties, parent, terminated, created_at, last_activity_at, executing_since FROM threads WHERE id = ?`,
|
|
24068
|
+
id
|
|
24069
|
+
);
|
|
24020
24070
|
const rows = cursor.toArray();
|
|
24021
24071
|
if (rows.length === 0) {
|
|
24022
24072
|
return null;
|
|
@@ -24036,7 +24086,12 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
24036
24086
|
properties,
|
|
24037
24087
|
parent: row.parent,
|
|
24038
24088
|
terminated: row.terminated,
|
|
24039
|
-
created_at: row.created_at
|
|
24089
|
+
created_at: row.created_at,
|
|
24090
|
+
last_activity_at: row.last_activity_at ?? row.created_at,
|
|
24091
|
+
executing: isThreadExecuting(
|
|
24092
|
+
row.executing_since,
|
|
24093
|
+
Math.floor(Date.now() / 1e3)
|
|
24094
|
+
)
|
|
24040
24095
|
};
|
|
24041
24096
|
}
|
|
24042
24097
|
/**
|
|
@@ -24077,6 +24132,7 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
24077
24132
|
*/
|
|
24078
24133
|
async listThreads(params) {
|
|
24079
24134
|
await this.ensureMigrated();
|
|
24135
|
+
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
24080
24136
|
const whereClauses = [];
|
|
24081
24137
|
const args = [];
|
|
24082
24138
|
if (params?.agent_name) {
|
|
@@ -24112,6 +24168,18 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
24112
24168
|
whereClauses.push("created_at <= ?");
|
|
24113
24169
|
args.push(params.endDate);
|
|
24114
24170
|
}
|
|
24171
|
+
if (params?.executing === true) {
|
|
24172
|
+
whereClauses.push("executing_since IS NOT NULL AND executing_since > ?");
|
|
24173
|
+
args.push(nowSeconds - EXECUTING_STALE_AFTER_SECONDS);
|
|
24174
|
+
} else if (params?.executing === false) {
|
|
24175
|
+
whereClauses.push("(executing_since IS NULL OR executing_since <= ?)");
|
|
24176
|
+
args.push(nowSeconds - EXECUTING_STALE_AFTER_SECONDS);
|
|
24177
|
+
}
|
|
24178
|
+
if (params?.terminated === true) {
|
|
24179
|
+
whereClauses.push("terminated IS NOT NULL");
|
|
24180
|
+
} else if (params?.terminated === false) {
|
|
24181
|
+
whereClauses.push("terminated IS NULL");
|
|
24182
|
+
}
|
|
24115
24183
|
const whereClause = whereClauses.length > 0 ? `WHERE ${whereClauses.join(" AND ")}` : "";
|
|
24116
24184
|
const countCursor = await this.ctx.storage.sql.exec(
|
|
24117
24185
|
`SELECT COUNT(*) as count FROM threads ${whereClause}`,
|
|
@@ -24120,10 +24188,11 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
24120
24188
|
const total = countCursor.one().count;
|
|
24121
24189
|
const limit = params?.limit ?? 100;
|
|
24122
24190
|
const offset = params?.offset ?? 0;
|
|
24191
|
+
const orderByClause = params?.sort === "created" ? "created_at DESC" : params?.sort === "oldest" ? "created_at ASC" : "COALESCE(last_activity_at, created_at) DESC, created_at DESC";
|
|
24123
24192
|
const cursor = await this.ctx.storage.sql.exec(
|
|
24124
|
-
`SELECT id, agent_name, user_id, tags, properties, parent, terminated, created_at FROM threads
|
|
24193
|
+
`SELECT id, agent_name, user_id, tags, properties, parent, terminated, created_at, last_activity_at, executing_since FROM threads
|
|
24125
24194
|
${whereClause}
|
|
24126
|
-
ORDER BY
|
|
24195
|
+
ORDER BY ${orderByClause}
|
|
24127
24196
|
LIMIT ? OFFSET ?`,
|
|
24128
24197
|
...args,
|
|
24129
24198
|
limit,
|
|
@@ -24143,10 +24212,80 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
24143
24212
|
properties: row.properties ? JSON.parse(row.properties) : null,
|
|
24144
24213
|
parent: row.parent,
|
|
24145
24214
|
terminated: row.terminated,
|
|
24146
|
-
created_at: row.created_at
|
|
24215
|
+
created_at: row.created_at,
|
|
24216
|
+
last_activity_at: row.last_activity_at ?? row.created_at,
|
|
24217
|
+
executing: isThreadExecuting(row.executing_since, nowSeconds)
|
|
24147
24218
|
}));
|
|
24148
24219
|
return { threads, total };
|
|
24149
24220
|
}
|
|
24221
|
+
/**
|
|
24222
|
+
* Distinct owners of threads visible to the caller, with counts, so a thread
|
|
24223
|
+
* list can offer an "owner" filter without exposing the admin-only user
|
|
24224
|
+
* directory (which is unavailable on hosted instances).
|
|
24225
|
+
*/
|
|
24226
|
+
async listThreadOwners(params) {
|
|
24227
|
+
await this.ensureMigrated();
|
|
24228
|
+
const whereClause = params?.user_id ? "WHERE t.user_id = ?" : "";
|
|
24229
|
+
const args = params?.user_id ? [params.user_id] : [];
|
|
24230
|
+
const cursor = await this.ctx.storage.sql.exec(
|
|
24231
|
+
`SELECT t.user_id AS user_id,
|
|
24232
|
+
u.username AS username,
|
|
24233
|
+
u.display_name AS display_name,
|
|
24234
|
+
u.email AS email,
|
|
24235
|
+
COUNT(*) AS thread_count
|
|
24236
|
+
FROM threads t
|
|
24237
|
+
LEFT JOIN users u ON u.id = t.user_id
|
|
24238
|
+
${whereClause}
|
|
24239
|
+
GROUP BY t.user_id
|
|
24240
|
+
ORDER BY thread_count DESC`,
|
|
24241
|
+
...args
|
|
24242
|
+
);
|
|
24243
|
+
return cursor.toArray();
|
|
24244
|
+
}
|
|
24245
|
+
/**
|
|
24246
|
+
* Record that a thread did work: stamp `last_activity_at` and flip the
|
|
24247
|
+
* executing marker. Activity bubbles up the parent chain so a root thread
|
|
24248
|
+
* sorts by the freshest work anywhere in its subagent tree — otherwise a
|
|
24249
|
+
* long-running subagent would let its parent sink down an activity-sorted
|
|
24250
|
+
* list.
|
|
24251
|
+
*/
|
|
24252
|
+
async recordThreadActivity(threadId, options) {
|
|
24253
|
+
await this.ensureMigrated();
|
|
24254
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
24255
|
+
const executing = options?.executing;
|
|
24256
|
+
await this.ctx.storage.sql.exec(
|
|
24257
|
+
`UPDATE threads
|
|
24258
|
+
SET last_activity_at = ?
|
|
24259
|
+
WHERE id IN (
|
|
24260
|
+
WITH RECURSIVE ancestry(id, parent) AS (
|
|
24261
|
+
SELECT id, parent FROM threads WHERE id = ?
|
|
24262
|
+
UNION ALL
|
|
24263
|
+
SELECT t.id, t.parent FROM threads t JOIN ancestry a ON t.id = a.parent
|
|
24264
|
+
)
|
|
24265
|
+
SELECT id FROM ancestry
|
|
24266
|
+
)`,
|
|
24267
|
+
now,
|
|
24268
|
+
threadId
|
|
24269
|
+
);
|
|
24270
|
+
if (executing === true) {
|
|
24271
|
+
await this.ctx.storage.sql.exec(
|
|
24272
|
+
`UPDATE threads SET executing_since = ? WHERE id = ? AND executing_since IS NULL`,
|
|
24273
|
+
now,
|
|
24274
|
+
threadId
|
|
24275
|
+
);
|
|
24276
|
+
} else if (executing === false) {
|
|
24277
|
+
await this.ctx.storage.sql.exec(
|
|
24278
|
+
`UPDATE threads SET executing_since = NULL WHERE id = ?`,
|
|
24279
|
+
threadId
|
|
24280
|
+
);
|
|
24281
|
+
}
|
|
24282
|
+
this.broadcastEvent({
|
|
24283
|
+
type: "thread_activity",
|
|
24284
|
+
threadId,
|
|
24285
|
+
last_activity_at: now,
|
|
24286
|
+
executing: executing === true
|
|
24287
|
+
});
|
|
24288
|
+
}
|
|
24150
24289
|
/**
|
|
24151
24290
|
* Delete a thread from the registry.
|
|
24152
24291
|
*/
|