@lightcone-ai/daemon 0.15.65 → 0.15.66

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightcone-ai/daemon",
3
- "version": "0.15.65",
3
+ "version": "0.15.66",
4
4
  "type": "module",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -1629,6 +1629,17 @@ export class AgentManager {
1629
1629
  }
1630
1630
  }
1631
1631
 
1632
+ _reportTurnUsage(connection, { agentId, workspaceId, agent, usage = null }) {
1633
+ connection.send({
1634
+ type: 'agent:turn_usage',
1635
+ agentId,
1636
+ workspaceId,
1637
+ sessionId: agent?.sessionId ?? null,
1638
+ runtime: agent?.runtime ?? null,
1639
+ usage,
1640
+ });
1641
+ }
1642
+
1632
1643
  async _postInternalActionComplete({ agentId, actionId, ok, result, error }) {
1633
1644
  const url = `${this.serverUrl.replace(/\/$/, '')}/internal/agent/${encodeURIComponent(agentId)}/actions/${encodeURIComponent(actionId)}/complete`;
1634
1645
  const res = await fetch(url, {
@@ -1985,6 +1996,7 @@ export class AgentManager {
1985
1996
  case 'turn_end':
1986
1997
  agent.kimiIdle = true;
1987
1998
  this._resetVisibleReplyTracking(agent);
1999
+ this._reportTurnUsage(connection, { agentId, workspaceId, agent });
1988
2000
  this._emitLifecycle(connection, {
1989
2001
  agentId,
1990
2002
  workspaceId,
@@ -2077,6 +2089,7 @@ export class AgentManager {
2077
2089
  agent.codexVisibleTextSeen = false;
2078
2090
  agent.codexSendMessageUsed = false;
2079
2091
  this._resetVisibleReplyTracking(agent);
2092
+ this._reportTurnUsage(connection, { agentId, workspaceId, agent, usage: evt.usage ?? null });
2080
2093
  this._emitLifecycle(connection, {
2081
2094
  agentId,
2082
2095
  workspaceId,
@@ -2195,6 +2208,7 @@ export class AgentManager {
2195
2208
  }
2196
2209
  this._resetVisibleReplyTracking(agent);
2197
2210
  console.log(`[AgentManager][${displayName}] turn done (stop_reason=${event.stop_reason ?? '?'})`);
2211
+ this._reportTurnUsage(connection, { agentId, workspaceId, agent, usage: event.usage ?? null });
2198
2212
  this._emitLifecycle(connection, {
2199
2213
  agentId,
2200
2214
  workspaceId,
@@ -306,7 +306,7 @@ export function parseCodexLine(line) {
306
306
  break;
307
307
  }
308
308
  case 'turn.completed':
309
- events.push({ kind: 'turn_end' });
309
+ events.push({ kind: 'turn_end', usage: event.usage && typeof event.usage === 'object' ? event.usage : null });
310
310
  break;
311
311
  case 'turn.failed':
312
312
  if (event.error?.message) events.push({ kind: 'error', message: event.error.message });
@@ -20,8 +20,6 @@ const TEXT_EXTS = new Set([
20
20
  '.csv', '.xml', '.yaml', '.yml', '.sh',
21
21
  ]);
22
22
 
23
- const LARGE_FILE_THRESHOLD = 5 * 1024 * 1024; // 5MB
24
-
25
23
  export function resolveWorkspaceFileUploadPlan({ localPath, workspacePath }) {
26
24
  const target = String(workspacePath ?? '').trim() || String(localPath ?? '').trim();
27
25
  const ext = extname(target).toLowerCase();
@@ -36,9 +34,11 @@ function sha256ofBuffer(buf) {
36
34
  }
37
35
 
38
36
  /**
39
- * Upload a local file to the workspace via the new presign → PUT → confirm flow.
40
- * For large files (>= 5MB), presign returns immediately (DB status = uploading)
41
- * and the PUT + confirm happen in the background.
37
+ * Upload a local file to the workspace via the presign → PUT → confirm flow.
38
+ * The PUT + confirm are awaited: a fire-and-forget background upload could be
39
+ * abandoned when the agent run / daemon process ends, leaving the DB row stuck
40
+ * at object_status='uploading' forever (the file then 202s "uploading" on every
41
+ * read). Blocking the tool call for a few seconds is cheaper than that.
42
42
  */
43
43
  async function uploadBinaryFile({
44
44
  localPath,
@@ -64,25 +64,13 @@ async function uploadBinaryFile({
64
64
  return { mode: 'object-storage', mime, bytes: size, objectKey, deduped: true };
65
65
  }
66
66
 
67
- const isLarge = size >= LARGE_FILE_THRESHOLD;
68
-
69
- const doPut = async () => {
70
- const resp = await fetch(uploadUrl, {
71
- method: 'PUT',
72
- body: buf,
73
- headers: { 'Content-Type': mime, 'Content-Length': String(size) },
74
- });
75
- if (!resp.ok) throw new Error(`COS PUT failed: ${resp.status} ${await resp.text()}`);
76
- await confirmUpload({ workspaceId, path: workspacePath, objectKey });
77
- };
78
-
79
- if (isLarge) {
80
- // Fire-and-forget for large files; server already wrote `uploading` status
81
- doPut().catch(err => console.error('[workspace-upload] large file background upload failed:', err?.message));
82
- return { mode: 'object-storage', mime, bytes: size, objectKey, async: true };
83
- }
84
-
85
- await doPut();
67
+ const resp = await fetch(uploadUrl, {
68
+ method: 'PUT',
69
+ body: buf,
70
+ headers: { 'Content-Type': mime, 'Content-Length': String(size) },
71
+ });
72
+ if (!resp.ok) throw new Error(`COS PUT failed: ${resp.status} ${await resp.text()}`);
73
+ await confirmUpload({ workspaceId, path: workspacePath, objectKey });
86
74
  return { mode: 'object-storage', mime, bytes: size, objectKey, async: false };
87
75
  }
88
76