comisai 1.0.12 → 1.0.14

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.
Files changed (24) hide show
  1. package/node_modules/@comis/agent/dist/bootstrap/sections/core-sections.js +4 -1
  2. package/node_modules/@comis/agent/dist/executor/pi-executor.d.ts +4 -1
  3. package/node_modules/@comis/agent/dist/executor/prompt-assembly.js +3 -0
  4. package/node_modules/@comis/agent/dist/model/operation-model-defaults.js +1 -0
  5. package/node_modules/@comis/agent/dist/session/comis-session-manager.js +9 -9
  6. package/node_modules/@comis/agent/package.json +1 -1
  7. package/node_modules/@comis/channels/package.json +1 -1
  8. package/node_modules/@comis/cli/package.json +1 -1
  9. package/node_modules/@comis/core/dist/event-bus/events-infra.d.ts +2 -0
  10. package/node_modules/@comis/core/package.json +1 -1
  11. package/node_modules/@comis/daemon/dist/wiring/setup-channels.js +13 -2
  12. package/node_modules/@comis/daemon/dist/wiring/setup-gateway.js +1 -0
  13. package/node_modules/@comis/daemon/dist/wiring/setup-schedulers.js +1 -0
  14. package/node_modules/@comis/daemon/package.json +1 -1
  15. package/node_modules/@comis/gateway/package.json +1 -1
  16. package/node_modules/@comis/infra/package.json +1 -1
  17. package/node_modules/@comis/memory/package.json +1 -1
  18. package/node_modules/@comis/scheduler/dist/cron/cron-types.d.ts +6 -0
  19. package/node_modules/@comis/scheduler/dist/cron/cron-types.js +2 -0
  20. package/node_modules/@comis/scheduler/package.json +1 -1
  21. package/node_modules/@comis/shared/package.json +1 -1
  22. package/node_modules/@comis/skills/dist/builtin/platform/gateway-tool.d.ts +1 -1
  23. package/node_modules/@comis/skills/package.json +1 -1
  24. package/package.json +12 -12
@@ -127,7 +127,10 @@ export function buildInboundMetadataSection(meta, _isMinimal) {
127
127
  "This is the metadata for the message you are currently responding to.",
128
128
  "Do not reveal these internal identifiers to the user.",
129
129
  ];
130
- if (meta.flags.isScheduled) {
130
+ if (meta.flags.isCronAgentTurn) {
131
+ lines.push("", "**CRON AGENT TURN:** This is an autonomous scheduled execution — you were invoked by a cron job to check on something, NOT by a user message.", "Use your tools to gather current data, then decide whether there is anything worth reporting.", "If there is nothing actionable or noteworthy to report, respond with exactly NO_REPLY — the system will suppress delivery and the user will not be disturbed.", "If there IS something to report, respond with a concise, actionable message for the user.", "Do NOT use the message tool (the system delivers your response automatically).");
132
+ }
133
+ else if (meta.flags.isScheduled) {
131
134
  lines.push("", "**SCHEDULED REMINDER:** This message is a scheduled reminder delivery, NOT a new user request.", "Your job is to deliver the reminder content to the user in a friendly, concise way.", "Do NOT ask follow-up questions, offer to reschedule, or search for context.", "Respond directly with the reminder text — do NOT use the message tool (the system delivers your response automatically).", "Do NOT respond with NO_REPLY or empty text.");
132
135
  }
133
136
  return lines;
@@ -50,7 +50,10 @@ import type { AgentExecutor } from "./types.js";
50
50
  *
51
51
  * Extracted as a named function for independent unit testing.
52
52
  */
53
- export declare function createBeforeToolCallGuard(stepCounter: StepCounter, budgetGuard: BudgetGuard, circuitBreaker: CircuitBreaker, toolRetryBreaker?: ToolRetryBreaker, messageSendLimiter?: MessageSendLimiter): (context: unknown, _signal?: AbortSignal) => Promise<import("../safety/message-send-limiter.js").MessageSendVerdict | undefined>;
53
+ export declare function createBeforeToolCallGuard(stepCounter: StepCounter, budgetGuard: BudgetGuard, circuitBreaker: CircuitBreaker, toolRetryBreaker?: ToolRetryBreaker, messageSendLimiter?: MessageSendLimiter): (context: unknown, _signal?: AbortSignal) => Promise<{
54
+ block: boolean;
55
+ reason: string;
56
+ } | undefined>;
54
57
  /**
55
58
  * Merge SDK session stats into execution result for token totals (R-13).
56
59
  *
@@ -189,6 +189,9 @@ function buildMessageFlags(msg) {
189
189
  if (meta.isScheduled === true) {
190
190
  flags.isScheduled = true;
191
191
  }
192
+ if (meta.isCronAgentTurn === true) {
193
+ flags.isCronAgentTurn = true;
194
+ }
192
195
  return flags;
193
196
  }
194
197
  /**
@@ -75,4 +75,5 @@ export const OPERATION_CACHE_DEFAULTS = {
75
75
  compaction: "none",
76
76
  taskExtraction: "none",
77
77
  condensation: "short",
78
+ cron: "short", // 5m TTL: covers within-execution multi-step reuse, avoids 1h write premium across hourly runs.
78
79
  };
@@ -55,15 +55,15 @@ export function createComisSessionManager(deps) {
55
55
  },
56
56
  async destroySession(sessionKey) {
57
57
  const sessionPath = sessionKeyToPath(sessionKey, deps.sessionBaseDir);
58
- try {
59
- await unlink(sessionPath);
60
- }
61
- catch {
62
- // File may not exist -- that's fine (already destroyed or never created)
63
- }
64
- // Clean up offloaded tool results
65
- const toolResultsDir = safePath(dirname(sessionPath), "tool-results");
66
- await suppressError(rm(toolResultsDir, { recursive: true, force: true }), "tool-results dir may not exist");
58
+ const sessionKeyStr = formatSessionKey(sessionKey);
59
+ await withSessionLock(deps.lockDir, sessionKeyStr, async () => {
60
+ try {
61
+ await unlink(sessionPath);
62
+ }
63
+ catch { /* ENOENT ok */ }
64
+ const toolResultsDir = safePath(dirname(sessionPath), "tool-results");
65
+ await suppressError(rm(toolResultsDir, { recursive: true, force: true }), "tool-results dir may not exist");
66
+ }, { retries: 10, retryMinTimeout: 500 });
67
67
  },
68
68
  writeSessionMetadata(sessionKey, metadata) {
69
69
  const sessionPath = sessionKeyToPath(sessionKey, deps.sessionBaseDir);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@comis/agent",
3
3
  "private": true,
4
- "version": "1.0.12",
4
+ "version": "1.0.14",
5
5
  "author": "Moshe Anconina",
6
6
  "license": "Apache-2.0",
7
7
  "description": "AI agent executor, budget control, and session management for Comis",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@comis/channels",
3
3
  "private": true,
4
- "version": "1.0.12",
4
+ "version": "1.0.14",
5
5
  "author": "Moshe Anconina",
6
6
  "license": "Apache-2.0",
7
7
  "description": "Chat platform adapters — Discord, Telegram, Slack, WhatsApp, Signal, iMessage, IRC, LINE",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@comis/cli",
3
3
  "private": true,
4
- "version": "1.0.12",
4
+ "version": "1.0.14",
5
5
  "author": "Moshe Anconina",
6
6
  "license": "Apache-2.0",
7
7
  "description": "Command-line interface for the Comis AI agent platform",
@@ -187,6 +187,8 @@ export interface InfraEvents {
187
187
  maxHistoryTurns?: number;
188
188
  /** Per-cron-job model override from CronPayload.agent_turn.model. */
189
189
  cronJobModel?: string;
190
+ /** Per-cron-job cache retention override from CronJob config. */
191
+ cacheRetention?: "none" | "short" | "long";
190
192
  /** Callback for agent_turn jobs to report execution result back to the scheduler.
191
193
  * Called by the event handler after agent execution completes. */
192
194
  onComplete?: (result: {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@comis/core",
3
3
  "private": true,
4
- "version": "1.0.12",
4
+ "version": "1.0.14",
5
5
  "author": "Moshe Anconina",
6
6
  "license": "Apache-2.0",
7
7
  "description": "Core domain types, ports, event bus, security, and config for Comis",
@@ -159,7 +159,7 @@ export async function setupChannels(deps) {
159
159
  model: resolution.model,
160
160
  operationType: "cron",
161
161
  promptTimeout: { promptTimeoutMs: resolution.timeoutMs },
162
- cacheRetention: resolution.cacheRetention,
162
+ cacheRetention: payload.cacheRetention ?? resolution.cacheRetention,
163
163
  };
164
164
  logger.info({ jobName, model: resolution.model, source: resolution.source, agentId: payload.agentId }, "Cron model resolved");
165
165
  }
@@ -171,6 +171,15 @@ export async function setupChannels(deps) {
171
171
  // Fresh strategy — expire existing session before each execution
172
172
  if (sessionStrategy === "fresh") {
173
173
  sessionManager.expire(sessionKey);
174
+ const piAdapter = deps.piSessionAdapters?.get(payload.agentId)
175
+ ?? deps.piSessionAdapters?.get(defaultAgentId);
176
+ if (piAdapter) {
177
+ await piAdapter.destroySession(sessionKey);
178
+ }
179
+ else {
180
+ logger.warn({ agentId: payload.agentId, jobName, hint: "No piSessionAdapter found — JSONL may accumulate", errorKind: "config" }, "Cron fresh strategy could not destroy JSONL");
181
+ }
182
+ container.eventBus.emit("session:expired", { sessionKey, reason: "cron-fresh" });
174
183
  }
175
184
  const syntheticMsg = {
176
185
  id: `cron-${payload.jobId}-${Date.now()}`,
@@ -180,7 +189,7 @@ export async function setupChannels(deps) {
180
189
  text: resultText,
181
190
  timestamp: Date.now(),
182
191
  attachments: [],
183
- metadata: { isScheduled: true, jobId: payload.jobId, jobName },
192
+ metadata: { isCronAgentTurn: true, jobId: payload.jobId, jobName },
184
193
  };
185
194
  const execStartTs = Date.now();
186
195
  try {
@@ -584,10 +593,12 @@ export async function setupChannels(deps) {
584
593
  if (adapter) {
585
594
  // eslint-disable-next-line no-restricted-syntax -- intentional fire-and-forget
586
595
  adapter.destroySession(key).catch(() => { });
596
+ container.eventBus.emit("session:expired", { sessionKey: key, reason: "chat-reset" });
587
597
  return;
588
598
  }
589
599
  // Fallback: expire via session manager
590
600
  deps.sessionManager.expire(key);
601
+ container.eventBus.emit("session:expired", { sessionKey: key, reason: "chat-reset" });
591
602
  },
592
603
  getAvailableModels: () => [],
593
604
  getUsageBreakdown: () => {
@@ -549,6 +549,7 @@ export async function setupGateway(deps) {
549
549
  const adapter = piSessionAdapters?.get(execAgentId);
550
550
  if (adapter) {
551
551
  suppressError(adapter.destroySession(key), "fire-and-forget session destroy");
552
+ container.eventBus.emit("session:expired", { sessionKey: key, reason: "gateway-reset" });
552
553
  return;
553
554
  }
554
555
  },
@@ -109,6 +109,7 @@ export async function setupSchedulers(deps) {
109
109
  sessionStrategy: job.sessionStrategy,
110
110
  maxHistoryTurns: job.maxHistoryTurns,
111
111
  cronJobModel: job.payload.kind === "agent_turn" ? job.payload.model : undefined,
112
+ cacheRetention: job.cacheRetention,
112
113
  onComplete: deferredResolve,
113
114
  });
114
115
  // Forward isolated results to main session if requested
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@comis/daemon",
3
3
  "private": true,
4
- "version": "1.0.12",
4
+ "version": "1.0.14",
5
5
  "author": "Moshe Anconina",
6
6
  "license": "Apache-2.0",
7
7
  "description": "Background daemon and orchestrator for the Comis platform",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@comis/gateway",
3
3
  "private": true,
4
- "version": "1.0.12",
4
+ "version": "1.0.14",
5
5
  "author": "Moshe Anconina",
6
6
  "license": "Apache-2.0",
7
7
  "description": "HTTP, JSON-RPC, and WebSocket gateway for Comis",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@comis/infra",
3
3
  "private": true,
4
- "version": "1.0.12",
4
+ "version": "1.0.14",
5
5
  "author": "Moshe Anconina",
6
6
  "license": "Apache-2.0",
7
7
  "description": "Structured logging infrastructure for Comis",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@comis/memory",
3
3
  "private": true,
4
- "version": "1.0.12",
4
+ "version": "1.0.14",
5
5
  "author": "Moshe Anconina",
6
6
  "license": "Apache-2.0",
7
7
  "description": "SQLite memory, embeddings, and RAG storage for Comis agents",
@@ -138,6 +138,12 @@ export declare const CronJobSchema: z.ZodObject<{
138
138
  }>>;
139
139
  /** Number of recent turns to keep for rolling strategy (default 3). */
140
140
  maxHistoryTurns: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
141
+ /** Per-job cache retention override. Default inherits OPERATION_CACHE_DEFAULTS["cron"] = "short". */
142
+ cacheRetention: z.ZodOptional<z.ZodEnum<{
143
+ none: "none";
144
+ short: "short";
145
+ long: "long";
146
+ }>>;
141
147
  /** Delivery target for routing results to originating channel */
142
148
  deliveryTarget: z.ZodOptional<z.ZodObject<{
143
149
  channelId: z.ZodString;
@@ -96,6 +96,8 @@ export const CronJobSchema = z.strictObject({
96
96
  sessionStrategy: CronSessionStrategySchema.default("fresh"),
97
97
  /** Number of recent turns to keep for rolling strategy (default 3). */
98
98
  maxHistoryTurns: z.number().int().positive().default(3).optional(),
99
+ /** Per-job cache retention override. Default inherits OPERATION_CACHE_DEFAULTS["cron"] = "short". */
100
+ cacheRetention: z.enum(["none", "short", "long"]).optional(),
99
101
  /** Delivery target for routing results to originating channel */
100
102
  deliveryTarget: CronDeliveryTargetSchema.optional(),
101
103
  /** Whether this job is currently enabled */
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@comis/scheduler",
3
3
  "private": true,
4
- "version": "1.0.12",
4
+ "version": "1.0.14",
5
5
  "author": "Moshe Anconina",
6
6
  "license": "Apache-2.0",
7
7
  "description": "Task scheduling and cron management for Comis",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@comis/shared",
3
3
  "private": true,
4
- "version": "1.0.12",
4
+ "version": "1.0.14",
5
5
  "author": "Moshe Anconina",
6
6
  "license": "Apache-2.0",
7
7
  "description": "Shared types and utilities for the Comis platform",
@@ -21,7 +21,7 @@ import type { RpcCall } from "./cron-tool.js";
21
21
  export declare const GATEWAY_ACTIONS: readonly ["read", "patch", "apply", "restart", "schema", "status", "history", "diff", "rollback", "env_set", "env_list"];
22
22
  export type GatewayAction = typeof GATEWAY_ACTIONS[number];
23
23
  declare const GatewayToolParams: import("@sinclair/typebox").TObject<{
24
- action: import("@sinclair/typebox").TUnion<import("@sinclair/typebox").TLiteral<"status" | "read" | "patch" | "diff" | "apply" | "restart" | "schema" | "history" | "rollback" | "env_set" | "env_list">[]>;
24
+ action: import("@sinclair/typebox").TUnion<import("@sinclair/typebox").TLiteral<"status" | "read" | "patch" | "apply" | "restart" | "schema" | "history" | "diff" | "rollback" | "env_set" | "env_list">[]>;
25
25
  section: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
26
26
  key: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
27
27
  value: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnknown>;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@comis/skills",
3
3
  "private": true,
4
- "version": "1.0.12",
4
+ "version": "1.0.14",
5
5
  "author": "Moshe Anconina",
6
6
  "license": "Apache-2.0",
7
7
  "description": "Skill system, MCP integration, and tool sandbox for Comis agents",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "comisai",
3
- "version": "1.0.12",
3
+ "version": "1.0.14",
4
4
  "author": "Moshe Anconina",
5
5
  "license": "Apache-2.0",
6
6
  "description": "Security-first AI agent platform — connects AI agents to Discord, Telegram, Slack, WhatsApp, and more",
@@ -115,17 +115,17 @@
115
115
  "@comis/daemon"
116
116
  ],
117
117
  "dependencies": {
118
- "@comis/shared": "1.0.12",
119
- "@comis/core": "1.0.12",
120
- "@comis/infra": "1.0.12",
121
- "@comis/memory": "1.0.12",
122
- "@comis/gateway": "1.0.12",
123
- "@comis/skills": "1.0.12",
124
- "@comis/scheduler": "1.0.12",
125
- "@comis/agent": "1.0.12",
126
- "@comis/channels": "1.0.12",
127
- "@comis/cli": "1.0.12",
128
- "@comis/daemon": "1.0.12",
118
+ "@comis/shared": "1.0.14",
119
+ "@comis/core": "1.0.14",
120
+ "@comis/infra": "1.0.14",
121
+ "@comis/memory": "1.0.14",
122
+ "@comis/gateway": "1.0.14",
123
+ "@comis/skills": "1.0.14",
124
+ "@comis/scheduler": "1.0.14",
125
+ "@comis/agent": "1.0.14",
126
+ "@comis/channels": "1.0.14",
127
+ "@comis/cli": "1.0.14",
128
+ "@comis/daemon": "1.0.14",
129
129
  "@agentclientprotocol/sdk": "^0.15.0",
130
130
  "@clack/core": "^1.1.0",
131
131
  "@clack/prompts": "^1.1.0",