@agent-native/core 0.98.6 → 0.98.8
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/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +12 -0
- package/corpus/core/docs/content/external-agents.mdx +22 -12
- package/corpus/core/docs/content/locales/ar-SA/external-agents.mdx +8 -2
- package/corpus/core/docs/content/locales/de-DE/external-agents.mdx +8 -2
- package/corpus/core/docs/content/locales/es-ES/external-agents.mdx +8 -2
- package/corpus/core/docs/content/locales/fr-FR/external-agents.mdx +8 -2
- package/corpus/core/docs/content/locales/hi-IN/external-agents.mdx +8 -2
- package/corpus/core/docs/content/locales/ja-JP/external-agents.mdx +8 -2
- package/corpus/core/docs/content/locales/ko-KR/external-agents.mdx +8 -2
- package/corpus/core/docs/content/locales/pt-BR/external-agents.mdx +8 -2
- package/corpus/core/docs/content/locales/zh-CN/external-agents.mdx +8 -2
- package/corpus/core/docs/content/locales/zh-TW/external-agents.mdx +8 -2
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/a2a/handlers.ts +6 -5
- package/corpus/core/src/a2a/task-store.ts +63 -0
- package/corpus/core/src/client/session-replay.ts +90 -6
- package/corpus/core/src/integrations/adapters/slack.ts +110 -19
- package/corpus/core/src/integrations/identity.ts +103 -39
- package/corpus/core/src/integrations/pending-tasks-retry-job.ts +2 -1
- package/corpus/core/src/integrations/pending-tasks-store.ts +1 -1
- package/corpus/core/src/integrations/plugin.ts +215 -8
- package/corpus/core/src/integrations/types.ts +37 -0
- package/corpus/core/src/integrations/webhook-handler.ts +1 -0
- package/corpus/core/src/mcp/builtin-tools.ts +5 -2
- package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +4 -1
- package/corpus/templates/analytics/AGENTS.md +9 -9
- package/corpus/templates/analytics/changelog/2026-07-12-analytics-uses-the-full-in-app-agent-for-multi-step-incident.md +6 -0
- package/corpus/templates/analytics/server/handlers/session-replay.ts +15 -9
- package/corpus/templates/analytics/server/lib/session-replay-agent-context.ts +23 -5
- package/corpus/templates/analytics/server/lib/session-replay.ts +26 -5
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +4 -1
- package/corpus/templates/analytics/server/routes/api/session-replay/agent-diagnostics.json.get.ts +8 -5
- package/corpus/templates/analytics/server/routes/api/session-replay/agent-events.json.get.ts +8 -3
- package/corpus/templates/calendar/app/components/calendar/DeleteEventDialog.tsx +12 -2
- package/dist/a2a/handlers.d.ts.map +1 -1
- package/dist/a2a/handlers.js +6 -6
- package/dist/a2a/handlers.js.map +1 -1
- package/dist/a2a/task-store.d.ts +12 -0
- package/dist/a2a/task-store.d.ts.map +1 -1
- package/dist/a2a/task-store.js +54 -0
- package/dist/a2a/task-store.js.map +1 -1
- package/dist/client/session-replay.d.ts.map +1 -1
- package/dist/client/session-replay.js +71 -9
- package/dist/client/session-replay.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/integrations/adapters/slack.d.ts.map +1 -1
- package/dist/integrations/adapters/slack.js +94 -11
- package/dist/integrations/adapters/slack.js.map +1 -1
- package/dist/integrations/identity.d.ts +19 -2
- package/dist/integrations/identity.d.ts.map +1 -1
- package/dist/integrations/identity.js +76 -34
- package/dist/integrations/identity.js.map +1 -1
- package/dist/integrations/pending-tasks-retry-job.d.ts.map +1 -1
- package/dist/integrations/pending-tasks-retry-job.js +2 -1
- package/dist/integrations/pending-tasks-retry-job.js.map +1 -1
- package/dist/integrations/pending-tasks-store.js +1 -1
- package/dist/integrations/pending-tasks-store.js.map +1 -1
- package/dist/integrations/plugin.d.ts.map +1 -1
- package/dist/integrations/plugin.js +165 -9
- package/dist/integrations/plugin.js.map +1 -1
- package/dist/integrations/types.d.ts +32 -0
- package/dist/integrations/types.d.ts.map +1 -1
- package/dist/integrations/types.js.map +1 -1
- package/dist/integrations/webhook-handler.js +1 -0
- package/dist/integrations/webhook-handler.js.map +1 -1
- package/dist/mcp/builtin-tools.d.ts.map +1 -1
- package/dist/mcp/builtin-tools.js +5 -2
- package/dist/mcp/builtin-tools.js.map +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/progress/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/docs/content/external-agents.mdx +22 -12
- package/docs/content/locales/ar-SA/external-agents.mdx +8 -2
- package/docs/content/locales/de-DE/external-agents.mdx +8 -2
- package/docs/content/locales/es-ES/external-agents.mdx +8 -2
- package/docs/content/locales/fr-FR/external-agents.mdx +8 -2
- package/docs/content/locales/hi-IN/external-agents.mdx +8 -2
- package/docs/content/locales/ja-JP/external-agents.mdx +8 -2
- package/docs/content/locales/ko-KR/external-agents.mdx +8 -2
- package/docs/content/locales/pt-BR/external-agents.mdx +8 -2
- package/docs/content/locales/zh-CN/external-agents.mdx +8 -2
- package/docs/content/locales/zh-TW/external-agents.mdx +8 -2
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-store.js","sourceRoot":"","sources":["../../src/a2a/task-store.ts"],"names":[],"mappings":"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","sourcesContent":["import crypto from \"crypto\";\n\nimport { getDbExec, intType, isPostgres } from \"../db/client.js\";\nimport { ensureTableExists, ensureColumnExists } from \"../db/ddl-guard.js\";\nimport type { Task, Message, TaskState, Artifact } from \"./types.js\";\n\nlet _initPromise: Promise<void> | undefined;\n\nasync function ensureTable(): Promise<void> {\n if (!_initPromise) {\n _initPromise = (async () => {\n const client = getDbExec();\n const createSql = `\n CREATE TABLE IF NOT EXISTS a2a_tasks (\n id TEXT PRIMARY KEY,\n context_id TEXT,\n status_state TEXT NOT NULL DEFAULT 'submitted',\n status_message TEXT,\n status_timestamp TEXT NOT NULL,\n history TEXT NOT NULL DEFAULT '[]',\n artifacts TEXT NOT NULL DEFAULT '[]',\n metadata TEXT,\n created_at ${intType()} NOT NULL,\n updated_at ${intType()} NOT NULL\n )\n `;\n\n if (isPostgres()) {\n // PG-guard: probe information_schema before issuing DDL to avoid ACCESS\n // EXCLUSIVE lock contention in fresh background-worker processes.\n await ensureTableExists(\"a2a_tasks\", createSql);\n // Additive migration: owner_email column. Bound to the JWT-verified\n // caller at task-creation time so handleGet / handleCancel can reject\n // mismatched callers (the IDOR class fixed in PR #369). Existing rows\n // have NULL owner_email and remain accessible to legacy callers via\n // the legacy-token apiKeyEnv path; new rows are scoped from this point\n // forward.\n await ensureColumnExists(\n \"a2a_tasks\",\n \"owner_email\",\n `ALTER TABLE a2a_tasks ADD COLUMN IF NOT EXISTS owner_email TEXT`,\n );\n return;\n }\n\n // SQLite (local dev): no lock problem — keep the original behaviour.\n await client.execute(createSql);\n // Additive migration: owner_email column. Bound to the JWT-verified\n // caller at task-creation time so handleGet / handleCancel can reject\n // mismatched callers (the IDOR class fixed in PR #369). Existing rows\n // have NULL owner_email and remain accessible to legacy callers via\n // the legacy-token apiKeyEnv path; new rows are scoped from this point\n // forward.\n try {\n await client.execute(\n `ALTER TABLE a2a_tasks ADD COLUMN owner_email TEXT`,\n );\n } catch {\n // Column already exists — expected on every restart after first run.\n }\n })().catch((err) => {\n // Retry init on the next call after a failed startup.\n _initPromise = undefined;\n throw err;\n });\n }\n return _initPromise;\n}\n\nfunction taskFromRow(row: any): Task & { ownerEmail?: string | null } {\n return {\n id: row.id as string,\n contextId: (row.context_id as string) || undefined,\n status: {\n state: row.status_state as TaskState,\n message: row.status_message\n ? JSON.parse(row.status_message as string)\n : undefined,\n timestamp: row.status_timestamp as string,\n },\n history: JSON.parse(row.history as string),\n artifacts: JSON.parse(row.artifacts as string),\n metadata: row.metadata ? JSON.parse(row.metadata as string) : undefined,\n ownerEmail: (row.owner_email as string | null) ?? null,\n };\n}\n\nfunction getAffectedRowCount(result: unknown): number | undefined {\n const resultRecord = result as\n | {\n rowsAffected?: number;\n rowCount?: number;\n count?: number;\n }\n | undefined;\n return (\n resultRecord?.rowsAffected ?? resultRecord?.rowCount ?? resultRecord?.count\n );\n}\n\nexport async function createTask(\n message: Message,\n contextId?: string,\n metadata?: Record<string, unknown>,\n ownerEmail?: string | null,\n): Promise<Task> {\n await ensureTable();\n const client = getDbExec();\n const id = crypto.randomUUID();\n const now = Date.now();\n const timestamp = new Date().toISOString();\n\n const task: Task = {\n id,\n contextId,\n status: { state: \"submitted\", timestamp },\n history: [message],\n artifacts: [],\n metadata,\n };\n\n await client.execute({\n sql: `INSERT INTO a2a_tasks (id, context_id, status_state, status_timestamp, history, artifacts, metadata, owner_email, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n args: [\n id,\n contextId ?? null,\n \"submitted\",\n timestamp,\n JSON.stringify([message]),\n \"[]\",\n metadata ? JSON.stringify(metadata) : null,\n ownerEmail ?? null,\n now,\n now,\n ],\n });\n\n return task;\n}\n\n/**\n * Fetch the verified owner email recorded against a task at creation time.\n * Returns null when the task has no owner (legacy rows or unauthenticated\n * deployments) or when the task is missing.\n *\n * Used by `handleGet` / `handleCancel` to reject IDOR access — the JWT-\n * verified caller's email must match `owner_email` to read or cancel.\n */\nexport async function getTaskOwner(id: string): Promise<string | null> {\n await ensureTable();\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT owner_email FROM a2a_tasks WHERE id = ?`,\n args: [id],\n });\n if (rows.length === 0) return null;\n const ownerEmail = (rows[0] as any).owner_email;\n return typeof ownerEmail === \"string\" && ownerEmail ? ownerEmail : null;\n}\n\n/**\n * Atomically claim a task for processing. Only succeeds when the task is in\n * state 'submitted' or 'working' — flipping it to 'processing' so concurrent\n * processors can't pick it up twice. Returns the task if claimed, null if it\n * was already claimed/completed/missing.\n *\n * Used by the cross-platform async processor (`_process-task` route) to avoid\n * duplicate handler runs when retries fire.\n */\nexport async function claimA2ATaskForProcessing(\n id: string,\n): Promise<Task | null> {\n await ensureTable();\n const client = getDbExec();\n const now = Date.now();\n const timestamp = new Date().toISOString();\n\n const result = await client.execute({\n sql: `UPDATE a2a_tasks\n SET status_state = 'processing',\n status_timestamp = ?,\n updated_at = ?\n WHERE id = ?\n AND status_state IN ('submitted', 'working')`,\n args: [timestamp, now, id],\n });\n const affected = getAffectedRowCount(result);\n if (affected === 0) return null;\n\n const { rows } = await client.execute({\n sql: `SELECT * FROM a2a_tasks WHERE id = ?`,\n args: [id],\n });\n if (rows.length === 0) return null;\n return taskFromRow(rows[0]);\n}\n\nexport async function getA2ATaskDispatchState(id: string): Promise<{\n id: string;\n statusState: string;\n metadata: Record<string, unknown> | undefined;\n updatedAt: number;\n createdAt: number;\n} | null> {\n await ensureTable();\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT id, status_state, metadata, created_at, updated_at FROM a2a_tasks WHERE id = ?`,\n args: [id],\n });\n const row = rows[0] as any;\n if (!row) return null;\n return {\n id: row.id as string,\n statusState: row.status_state as string,\n metadata: row.metadata ? JSON.parse(row.metadata as string) : undefined,\n updatedAt: Number(row.updated_at ?? 0),\n createdAt: Number(row.created_at ?? 0),\n };\n}\n\nexport async function touchQueuedA2ATaskDispatch(id: string): Promise<boolean> {\n await ensureTable();\n const client = getDbExec();\n const now = Date.now();\n const result = await client.execute({\n sql: `UPDATE a2a_tasks\n SET updated_at = ?\n WHERE id = ?\n AND status_state IN ('submitted', 'working')`,\n args: [now, id],\n });\n const affected = getAffectedRowCount(result);\n return affected !== 0;\n}\n\nexport async function touchProcessingA2ATask(id: string): Promise<boolean> {\n await ensureTable();\n const client = getDbExec();\n const now = Date.now();\n const result = await client.execute({\n sql: `UPDATE a2a_tasks\n SET updated_at = ?\n WHERE id = ?\n AND status_state = 'processing'`,\n args: [now, id],\n });\n const affected = getAffectedRowCount(result);\n return affected !== 0;\n}\n\nexport async function resetStuckA2ATaskForRetry(\n id: string,\n processingCutoff: number,\n): Promise<boolean> {\n await ensureTable();\n const client = getDbExec();\n const now = Date.now();\n const timestamp = new Date().toISOString();\n const result = await client.execute({\n sql: `UPDATE a2a_tasks\n SET status_state = 'working',\n status_timestamp = ?,\n updated_at = ?\n WHERE id = ?\n AND status_state = 'processing'\n AND updated_at <= ?`,\n args: [timestamp, now, id, processingCutoff],\n });\n const affected = getAffectedRowCount(result);\n return affected !== 0;\n}\n\n/**\n * Fail a processing task once it is stuck. Two independent conditions can\n * trigger this, either of which alone is sufficient:\n * - `updated_at <= processingCutoff`: no heartbeat/progress touch in a\n * while — the processor likely died.\n * - `created_at <= createdAtCutoff` — a hard wall on total run time. A\n * hung await inside a still-alive process keeps `updated_at` fresh via\n * the liveness heartbeat forever, so staleness alone never trips; age\n * since creation is the only bound that catches it.\n */\nexport async function failStuckA2ATask(\n id: string,\n processingCutoff: number,\n reason: string,\n createdAtCutoff?: number,\n): Promise<boolean> {\n await ensureTable();\n const client = getDbExec();\n const now = Date.now();\n const timestamp = new Date().toISOString();\n const message: Message = {\n role: \"agent\",\n parts: [{ type: \"text\", text: reason }],\n };\n const ageCondition =\n createdAtCutoff !== undefined\n ? `AND (updated_at <= ? OR created_at <= ?)`\n : `AND updated_at <= ?`;\n const result = await client.execute({\n sql: `UPDATE a2a_tasks\n SET status_state = 'failed',\n status_message = ?,\n status_timestamp = ?,\n updated_at = ?\n WHERE id = ?\n AND status_state = 'processing'\n ${ageCondition}`,\n args:\n createdAtCutoff !== undefined\n ? [\n JSON.stringify(message),\n timestamp,\n now,\n id,\n processingCutoff,\n createdAtCutoff,\n ]\n : [JSON.stringify(message), timestamp, now, id, processingCutoff],\n });\n const affected = getAffectedRowCount(result);\n return affected !== 0;\n}\n\n/**\n * Fail a queued (submitted/working) task whose age since creation exceeds\n * `createdAtCutoff` — the dispatch-retry loop kept throttling/refiring\n * without ever reaching `processing`. Mirrors `failStuckA2ATask` but is\n * gated on the queued state set and on `created_at` (queued tasks have no\n * heartbeat, so staleness of `updated_at` isn't a meaningful signal here).\n */\nexport async function failStuckQueuedA2ATask(\n id: string,\n createdAtCutoff: number,\n reason: string,\n): Promise<boolean> {\n await ensureTable();\n const client = getDbExec();\n const now = Date.now();\n const timestamp = new Date().toISOString();\n const message: Message = {\n role: \"agent\",\n parts: [{ type: \"text\", text: reason }],\n };\n const result = await client.execute({\n sql: `UPDATE a2a_tasks\n SET status_state = 'failed',\n status_message = ?,\n status_timestamp = ?,\n updated_at = ?\n WHERE id = ?\n AND status_state IN ('submitted', 'working')\n AND created_at <= ?`,\n args: [JSON.stringify(message), timestamp, now, id, createdAtCutoff],\n });\n const affected = getAffectedRowCount(result);\n return affected !== 0;\n}\n\nexport async function getTask(id: string): Promise<Task | null> {\n await ensureTable();\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT * FROM a2a_tasks WHERE id = ?`,\n args: [id],\n });\n if (rows.length === 0) return null;\n return taskFromRow(rows[0]);\n}\n\nexport async function updateTask(\n id: string,\n update: {\n state?: TaskState;\n message?: Message;\n artifacts?: Artifact[];\n },\n): Promise<Task | null> {\n await ensureTable();\n const client = getDbExec();\n\n // Read current task\n const { rows } = await client.execute({\n sql: `SELECT * FROM a2a_tasks WHERE id = ?`,\n args: [id],\n });\n if (rows.length === 0) return null;\n\n const task = taskFromRow(rows[0]);\n const now = Date.now();\n\n if (update.state) {\n task.status = {\n state: update.state,\n message: update.message ?? task.status.message,\n timestamp: new Date().toISOString(),\n };\n }\n\n if (update.message && task.history) {\n task.history.push(update.message);\n }\n\n if (update.artifacts) {\n task.artifacts = [...(task.artifacts ?? []), ...update.artifacts];\n }\n\n await client.execute({\n sql: `UPDATE a2a_tasks SET status_state = ?, status_message = ?, status_timestamp = ?, history = ?, artifacts = ?, updated_at = ? WHERE id = ?`,\n args: [\n task.status.state,\n task.status.message ? JSON.stringify(task.status.message) : null,\n task.status.timestamp,\n JSON.stringify(task.history),\n JSON.stringify(task.artifacts),\n now,\n id,\n ],\n });\n\n return task;\n}\n\nexport async function updateTaskStatusMessage(\n id: string,\n message: Message,\n): Promise<void> {\n await ensureTable();\n const client = getDbExec();\n const now = Date.now();\n const timestamp = new Date().toISOString();\n await client.execute({\n sql: `UPDATE a2a_tasks\n SET status_message = ?,\n status_timestamp = ?,\n updated_at = ?\n WHERE id = ?\n AND status_state IN ('submitted', 'working', 'processing')`,\n args: [JSON.stringify(message), timestamp, now, id],\n });\n}\n\nexport async function listTasks(contextId?: string): Promise<Task[]> {\n await ensureTable();\n const client = getDbExec();\n\n if (contextId) {\n const { rows } = await client.execute({\n sql: `SELECT * FROM a2a_tasks WHERE context_id = ? ORDER BY created_at DESC`,\n args: [contextId],\n });\n return rows.map(taskFromRow);\n }\n\n const { rows } = await client.execute(\n `SELECT * FROM a2a_tasks ORDER BY created_at DESC`,\n );\n return rows.map(taskFromRow);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"task-store.js","sourceRoot":"","sources":["../../src/a2a/task-store.ts"],"names":[],"mappings":"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","sourcesContent":["import crypto from \"crypto\";\n\nimport { getDbExec, intType, isPostgres } from \"../db/client.js\";\nimport { ensureTableExists, ensureColumnExists } from \"../db/ddl-guard.js\";\nimport type { Task, Message, TaskState, Artifact } from \"./types.js\";\n\nlet _initPromise: Promise<void> | undefined;\n\nasync function ensureTable(): Promise<void> {\n if (!_initPromise) {\n _initPromise = (async () => {\n const client = getDbExec();\n const createSql = `\n CREATE TABLE IF NOT EXISTS a2a_tasks (\n id TEXT PRIMARY KEY,\n context_id TEXT,\n status_state TEXT NOT NULL DEFAULT 'submitted',\n status_message TEXT,\n status_timestamp TEXT NOT NULL,\n history TEXT NOT NULL DEFAULT '[]',\n artifacts TEXT NOT NULL DEFAULT '[]',\n metadata TEXT,\n created_at ${intType()} NOT NULL,\n updated_at ${intType()} NOT NULL\n )\n `;\n\n if (isPostgres()) {\n // PG-guard: probe information_schema before issuing DDL to avoid ACCESS\n // EXCLUSIVE lock contention in fresh background-worker processes.\n await ensureTableExists(\"a2a_tasks\", createSql);\n // Additive migration: owner_email column. Bound to the JWT-verified\n // caller at task-creation time so handleGet / handleCancel can reject\n // mismatched callers (the IDOR class fixed in PR #369). Existing rows\n // have NULL owner_email and remain accessible to legacy callers via\n // the legacy-token apiKeyEnv path; new rows are scoped from this point\n // forward.\n await ensureColumnExists(\n \"a2a_tasks\",\n \"owner_email\",\n `ALTER TABLE a2a_tasks ADD COLUMN IF NOT EXISTS owner_email TEXT`,\n );\n return;\n }\n\n // SQLite (local dev): no lock problem — keep the original behaviour.\n await client.execute(createSql);\n // Additive migration: owner_email column. Bound to the JWT-verified\n // caller at task-creation time so handleGet / handleCancel can reject\n // mismatched callers (the IDOR class fixed in PR #369). Existing rows\n // have NULL owner_email and remain accessible to legacy callers via\n // the legacy-token apiKeyEnv path; new rows are scoped from this point\n // forward.\n try {\n await client.execute(\n `ALTER TABLE a2a_tasks ADD COLUMN owner_email TEXT`,\n );\n } catch {\n // Column already exists — expected on every restart after first run.\n }\n })().catch((err) => {\n // Retry init on the next call after a failed startup.\n _initPromise = undefined;\n throw err;\n });\n }\n return _initPromise;\n}\n\nfunction taskFromRow(row: any): Task & { ownerEmail?: string | null } {\n return {\n id: row.id as string,\n contextId: (row.context_id as string) || undefined,\n status: {\n state: row.status_state as TaskState,\n message: row.status_message\n ? JSON.parse(row.status_message as string)\n : undefined,\n timestamp: row.status_timestamp as string,\n },\n history: JSON.parse(row.history as string),\n artifacts: JSON.parse(row.artifacts as string),\n metadata: row.metadata ? JSON.parse(row.metadata as string) : undefined,\n ownerEmail: (row.owner_email as string | null) ?? null,\n };\n}\n\nfunction getAffectedRowCount(result: unknown): number | undefined {\n const resultRecord = result as\n | {\n rowsAffected?: number;\n rowCount?: number;\n count?: number;\n }\n | undefined;\n return (\n resultRecord?.rowsAffected ?? resultRecord?.rowCount ?? resultRecord?.count\n );\n}\n\nexport async function createTask(\n message: Message,\n contextId?: string,\n metadata?: Record<string, unknown>,\n ownerEmail?: string | null,\n): Promise<Task> {\n await ensureTable();\n const client = getDbExec();\n const id = crypto.randomUUID();\n const now = Date.now();\n const timestamp = new Date().toISOString();\n\n const task: Task = {\n id,\n contextId,\n status: { state: \"submitted\", timestamp },\n history: [message],\n artifacts: [],\n metadata,\n };\n\n await client.execute({\n sql: `INSERT INTO a2a_tasks (id, context_id, status_state, status_timestamp, history, artifacts, metadata, owner_email, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n args: [\n id,\n contextId ?? null,\n \"submitted\",\n timestamp,\n JSON.stringify([message]),\n \"[]\",\n metadata ? JSON.stringify(metadata) : null,\n ownerEmail ?? null,\n now,\n now,\n ],\n });\n\n return task;\n}\n\n/**\n * Fetch the verified owner email recorded against a task at creation time.\n * Returns null when the task has no owner (legacy rows or unauthenticated\n * deployments) or when the task is missing.\n *\n * Used by `handleGet` / `handleCancel` to reject IDOR access — the JWT-\n * verified caller's email must match `owner_email` to read or cancel.\n */\nexport async function getTaskOwner(id: string): Promise<string | null> {\n await ensureTable();\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT owner_email FROM a2a_tasks WHERE id = ?`,\n args: [id],\n });\n if (rows.length === 0) return null;\n const ownerEmail = (rows[0] as any).owner_email;\n return typeof ownerEmail === \"string\" && ownerEmail ? ownerEmail : null;\n}\n\n/**\n * Atomically claim a task for processing. Only succeeds when the task is in\n * state 'submitted' or 'working' — flipping it to 'processing' so concurrent\n * processors can't pick it up twice. Returns the task if claimed, null if it\n * was already claimed/completed/missing.\n *\n * Used by the cross-platform async processor (`_process-task` route) to avoid\n * duplicate handler runs when retries fire.\n */\nexport async function claimA2ATaskForProcessing(\n id: string,\n): Promise<Task | null> {\n await ensureTable();\n const client = getDbExec();\n const now = Date.now();\n const timestamp = new Date().toISOString();\n\n const result = await client.execute({\n sql: `UPDATE a2a_tasks\n SET status_state = 'processing',\n status_timestamp = ?,\n updated_at = ?\n WHERE id = ?\n AND status_state IN ('submitted', 'working')`,\n args: [timestamp, now, id],\n });\n const affected = getAffectedRowCount(result);\n if (affected === 0) return null;\n\n const { rows } = await client.execute({\n sql: `SELECT * FROM a2a_tasks WHERE id = ?`,\n args: [id],\n });\n if (rows.length === 0) return null;\n return taskFromRow(rows[0]);\n}\n\nexport async function getA2ATaskDispatchState(id: string): Promise<{\n id: string;\n statusState: string;\n metadata: Record<string, unknown> | undefined;\n updatedAt: number;\n createdAt: number;\n} | null> {\n await ensureTable();\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT id, status_state, metadata, created_at, updated_at FROM a2a_tasks WHERE id = ?`,\n args: [id],\n });\n const row = rows[0] as any;\n if (!row) return null;\n return {\n id: row.id as string,\n statusState: row.status_state as string,\n metadata: row.metadata ? JSON.parse(row.metadata as string) : undefined,\n updatedAt: Number(row.updated_at ?? 0),\n createdAt: Number(row.created_at ?? 0),\n };\n}\n\nexport async function touchQueuedA2ATaskDispatch(id: string): Promise<boolean> {\n await ensureTable();\n const client = getDbExec();\n const now = Date.now();\n const result = await client.execute({\n sql: `UPDATE a2a_tasks\n SET updated_at = ?\n WHERE id = ?\n AND status_state IN ('submitted', 'working')`,\n args: [now, id],\n });\n const affected = getAffectedRowCount(result);\n return affected !== 0;\n}\n\nexport async function touchProcessingA2ATask(id: string): Promise<boolean> {\n await ensureTable();\n const client = getDbExec();\n const now = Date.now();\n const result = await client.execute({\n sql: `UPDATE a2a_tasks\n SET updated_at = ?\n WHERE id = ?\n AND status_state = 'processing'`,\n args: [now, id],\n });\n const affected = getAffectedRowCount(result);\n return affected !== 0;\n}\n\nexport async function resetStuckA2ATaskForRetry(\n id: string,\n processingCutoff: number,\n): Promise<boolean> {\n await ensureTable();\n const client = getDbExec();\n const now = Date.now();\n const timestamp = new Date().toISOString();\n const result = await client.execute({\n sql: `UPDATE a2a_tasks\n SET status_state = 'working',\n status_timestamp = ?,\n updated_at = ?\n WHERE id = ?\n AND status_state = 'processing'\n AND updated_at <= ?`,\n args: [timestamp, now, id, processingCutoff],\n });\n const affected = getAffectedRowCount(result);\n return affected !== 0;\n}\n\n/**\n * Fail a processing task once it is stuck. Two independent conditions can\n * trigger this, either of which alone is sufficient:\n * - `updated_at <= processingCutoff`: no heartbeat/progress touch in a\n * while — the processor likely died.\n * - `created_at <= createdAtCutoff` — a hard wall on total run time. A\n * hung await inside a still-alive process keeps `updated_at` fresh via\n * the liveness heartbeat forever, so staleness alone never trips; age\n * since creation is the only bound that catches it.\n */\nexport async function failStuckA2ATask(\n id: string,\n processingCutoff: number,\n reason: string,\n createdAtCutoff?: number,\n): Promise<boolean> {\n await ensureTable();\n const client = getDbExec();\n const now = Date.now();\n const timestamp = new Date().toISOString();\n const message: Message = {\n role: \"agent\",\n parts: [{ type: \"text\", text: reason }],\n };\n const ageCondition =\n createdAtCutoff !== undefined\n ? `AND (updated_at <= ? OR created_at <= ?)`\n : `AND updated_at <= ?`;\n const result = await client.execute({\n sql: `UPDATE a2a_tasks\n SET status_state = 'failed',\n status_message = ?,\n status_timestamp = ?,\n updated_at = ?\n WHERE id = ?\n AND status_state = 'processing'\n ${ageCondition}`,\n args:\n createdAtCutoff !== undefined\n ? [\n JSON.stringify(message),\n timestamp,\n now,\n id,\n processingCutoff,\n createdAtCutoff,\n ]\n : [JSON.stringify(message), timestamp, now, id, processingCutoff],\n });\n const affected = getAffectedRowCount(result);\n return affected !== 0;\n}\n\n/**\n * Fail a queued (submitted/working) task whose age since creation exceeds\n * `createdAtCutoff` — the dispatch-retry loop kept throttling/refiring\n * without ever reaching `processing`. Mirrors `failStuckA2ATask` but is\n * gated on the queued state set and on `created_at` (queued tasks have no\n * heartbeat, so staleness of `updated_at` isn't a meaningful signal here).\n */\nexport async function failStuckQueuedA2ATask(\n id: string,\n createdAtCutoff: number,\n reason: string,\n): Promise<boolean> {\n await ensureTable();\n const client = getDbExec();\n const now = Date.now();\n const timestamp = new Date().toISOString();\n const message: Message = {\n role: \"agent\",\n parts: [{ type: \"text\", text: reason }],\n };\n const result = await client.execute({\n sql: `UPDATE a2a_tasks\n SET status_state = 'failed',\n status_message = ?,\n status_timestamp = ?,\n updated_at = ?\n WHERE id = ?\n AND status_state IN ('submitted', 'working')\n AND created_at <= ?`,\n args: [JSON.stringify(message), timestamp, now, id, createdAtCutoff],\n });\n const affected = getAffectedRowCount(result);\n return affected !== 0;\n}\n\nexport async function getTask(id: string): Promise<Task | null> {\n await ensureTable();\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT * FROM a2a_tasks WHERE id = ?`,\n args: [id],\n });\n if (rows.length === 0) return null;\n return taskFromRow(rows[0]);\n}\n\nexport async function updateTask(\n id: string,\n update: {\n state?: TaskState;\n message?: Message;\n artifacts?: Artifact[];\n },\n): Promise<Task | null> {\n await ensureTable();\n const client = getDbExec();\n\n // Read current task\n const { rows } = await client.execute({\n sql: `SELECT * FROM a2a_tasks WHERE id = ?`,\n args: [id],\n });\n if (rows.length === 0) return null;\n\n const task = taskFromRow(rows[0]);\n const now = Date.now();\n\n if (update.state) {\n task.status = {\n state: update.state,\n message: update.message ?? task.status.message,\n timestamp: new Date().toISOString(),\n };\n }\n\n if (update.message && task.history) {\n task.history.push(update.message);\n }\n\n if (update.artifacts) {\n task.artifacts = [...(task.artifacts ?? []), ...update.artifacts];\n }\n\n await client.execute({\n sql: `UPDATE a2a_tasks SET status_state = ?, status_message = ?, status_timestamp = ?, history = ?, artifacts = ?, updated_at = ? WHERE id = ?`,\n args: [\n task.status.state,\n task.status.message ? JSON.stringify(task.status.message) : null,\n task.status.timestamp,\n JSON.stringify(task.history),\n JSON.stringify(task.artifacts),\n now,\n id,\n ],\n });\n\n return task;\n}\n\n/**\n * Persist the terminal result produced by the async processor, but only while\n * that processor still owns a task in `processing`. A tasks/get request may\n * fail an over-lifetime processor while its handler is still running; the\n * handler cannot be canceled reliably, so this compare-and-set is what keeps\n * its eventual completion (or error) from overwriting the timeout result.\n */\nexport async function settleProcessingA2ATask(\n id: string,\n update: {\n state: \"completed\" | \"failed\";\n message?: Message;\n artifacts?: Artifact[];\n },\n): Promise<Task | null> {\n await ensureTable();\n const client = getDbExec();\n\n const { rows } = await client.execute({\n sql: `SELECT * FROM a2a_tasks WHERE id = ?`,\n args: [id],\n });\n if (rows.length === 0) return null;\n\n const task = taskFromRow(rows[0]);\n const now = Date.now();\n task.status = {\n state: update.state,\n message: update.message ?? task.status.message,\n timestamp: new Date().toISOString(),\n };\n if (update.message && task.history) {\n task.history.push(update.message);\n }\n if (update.artifacts) {\n task.artifacts = [...(task.artifacts ?? []), ...update.artifacts];\n }\n\n const result = await client.execute({\n sql: `UPDATE a2a_tasks\n SET status_state = ?,\n status_message = ?,\n status_timestamp = ?,\n history = ?,\n artifacts = ?,\n updated_at = ?\n WHERE id = ?\n AND status_state = 'processing'`,\n args: [\n task.status.state,\n task.status.message ? JSON.stringify(task.status.message) : null,\n task.status.timestamp,\n JSON.stringify(task.history),\n JSON.stringify(task.artifacts),\n now,\n id,\n ],\n });\n const affected = getAffectedRowCount(result);\n if (affected === 0) return null;\n return task;\n}\n\nexport async function updateTaskStatusMessage(\n id: string,\n message: Message,\n): Promise<void> {\n await ensureTable();\n const client = getDbExec();\n const now = Date.now();\n const timestamp = new Date().toISOString();\n await client.execute({\n sql: `UPDATE a2a_tasks\n SET status_message = ?,\n status_timestamp = ?,\n updated_at = ?\n WHERE id = ?\n AND status_state IN ('submitted', 'working', 'processing')`,\n args: [JSON.stringify(message), timestamp, now, id],\n });\n}\n\nexport async function listTasks(contextId?: string): Promise<Task[]> {\n await ensureTable();\n const client = getDbExec();\n\n if (contextId) {\n const { rows } = await client.execute({\n sql: `SELECT * FROM a2a_tasks WHERE context_id = ? ORDER BY created_at DESC`,\n args: [contextId],\n });\n return rows.map(taskFromRow);\n }\n\n const { rows } = await client.execute(\n `SELECT * FROM a2a_tasks ORDER BY created_at DESC`,\n );\n return rows.map(taskFromRow);\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-replay.d.ts","sourceRoot":"","sources":["../../src/client/session-replay.ts"],"names":[],"mappings":"AA6BA,MAAM,MAAM,uBAAuB,GAC/B,MAAM,GACN,MAAM,GACN,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"session-replay.d.ts","sourceRoot":"","sources":["../../src/client/session-replay.ts"],"names":[],"mappings":"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"}
|
|
@@ -120,12 +120,14 @@ function getState() {
|
|
|
120
120
|
g[SESSION_REPLAY_STATE_KEY] = {
|
|
121
121
|
active: false,
|
|
122
122
|
startPromise: null,
|
|
123
|
+
startGeneration: 0,
|
|
123
124
|
replayId: null,
|
|
124
125
|
startedAtMs: null,
|
|
125
126
|
sequence: 0,
|
|
126
127
|
queue: [],
|
|
127
128
|
queuedBytes: 0,
|
|
128
129
|
retryBatches: [],
|
|
130
|
+
transientClientErrorFailures: 0,
|
|
129
131
|
flushTimer: null,
|
|
130
132
|
maxDurationTimer: null,
|
|
131
133
|
flushing: false,
|
|
@@ -148,10 +150,12 @@ function getState() {
|
|
|
148
150
|
const state = g[SESSION_REPLAY_STATE_KEY];
|
|
149
151
|
// Keep Vite HMR safe when an older recorder state survives a module reload.
|
|
150
152
|
state.resourceNodes ??= new Map();
|
|
153
|
+
state.transientClientErrorFailures ??= 0;
|
|
151
154
|
state.restoreIframeBridge ??= null;
|
|
152
155
|
state.pendingFlushReason ??= null;
|
|
153
156
|
state.pendingFlushWaiters ??= [];
|
|
154
157
|
state.awaitingFullSnapshot ??= false;
|
|
158
|
+
state.startGeneration ??= 0;
|
|
155
159
|
return state;
|
|
156
160
|
}
|
|
157
161
|
// The replay session record (replayId + sequence counter) lives in
|
|
@@ -983,12 +987,17 @@ class ReplayUploadHttpError extends Error {
|
|
|
983
987
|
this.status = status;
|
|
984
988
|
}
|
|
985
989
|
}
|
|
986
|
-
/** 4xx statuses where retrying the exact same batch can never succeed
|
|
987
|
-
*
|
|
988
|
-
*
|
|
989
|
-
*
|
|
990
|
+
/** 4xx statuses where retrying the exact same batch can never succeed.
|
|
991
|
+
* Keep this deliberately narrow: 401/403/404 can be temporary during auth or
|
|
992
|
+
* deploy transitions, so they get a small retry budget before the rejected
|
|
993
|
+
* episode is stopped. The budget prevents a persistent configuration failure
|
|
994
|
+
* from pinning retryBatches while rrweb events grow without bound. */
|
|
990
995
|
function isDefinitiveReplayUploadClientError(status) {
|
|
991
|
-
return status
|
|
996
|
+
return status === 400 || status === 409 || status === 413 || status === 422;
|
|
997
|
+
}
|
|
998
|
+
const MAX_TRANSIENT_REPLAY_CLIENT_FAILURES = 3;
|
|
999
|
+
function isTransientReplayUploadClientError(status) {
|
|
1000
|
+
return status === 401 || status === 403 || status === 404;
|
|
992
1001
|
}
|
|
993
1002
|
async function sendReplayUpload(options, body, callbacks = {}) {
|
|
994
1003
|
if (isCrossOriginReplayEndpoint(options.endpoint)) {
|
|
@@ -1223,6 +1232,7 @@ export async function flushSessionReplay(reason = "manual") {
|
|
|
1223
1232
|
if (!reservedSequence)
|
|
1224
1233
|
advanceReplaySequence(state, payload);
|
|
1225
1234
|
state.automaticConflictRestartAttempted = false;
|
|
1235
|
+
state.transientClientErrorFailures = 0;
|
|
1226
1236
|
uploaded = true;
|
|
1227
1237
|
}
|
|
1228
1238
|
catch (error) {
|
|
@@ -1235,8 +1245,20 @@ export async function flushSessionReplay(reason = "manual") {
|
|
|
1235
1245
|
const rejectedStatus = error instanceof ReplayUploadHttpError ? error.status : null;
|
|
1236
1246
|
const splitBatch = rejectedStatus === 413 ? splitReplayBatch(events) : null;
|
|
1237
1247
|
const isUnsplittableOversizedBatch = rejectedStatus === 413 && splitBatch === null;
|
|
1248
|
+
const isTransientClientError = rejectedStatus !== null &&
|
|
1249
|
+
isTransientReplayUploadClientError(rejectedStatus);
|
|
1250
|
+
if (isTransientClientError) {
|
|
1251
|
+
state.transientClientErrorFailures += 1;
|
|
1252
|
+
}
|
|
1253
|
+
else {
|
|
1254
|
+
state.transientClientErrorFailures = 0;
|
|
1255
|
+
}
|
|
1256
|
+
const exhaustedTransientClientRetries = isTransientClientError &&
|
|
1257
|
+
state.transientClientErrorFailures >=
|
|
1258
|
+
MAX_TRANSIENT_REPLAY_CLIENT_FAILURES;
|
|
1238
1259
|
const isDefinitiveClientError = error instanceof ReplayUploadHttpError &&
|
|
1239
|
-
isDefinitiveReplayUploadClientError(error.status)
|
|
1260
|
+
(isDefinitiveReplayUploadClientError(error.status) ||
|
|
1261
|
+
exhaustedTransientClientRetries) &&
|
|
1240
1262
|
!splitBatch &&
|
|
1241
1263
|
!isUnsplittableOversizedBatch;
|
|
1242
1264
|
if (splitBatch) {
|
|
@@ -1382,6 +1404,21 @@ export async function flushSessionReplay(reason = "manual") {
|
|
|
1382
1404
|
* on internal option shapes continuing to round-trip through the public API.
|
|
1383
1405
|
*/
|
|
1384
1406
|
async function restartSessionReplayAfterConflict(state, options, sessionId) {
|
|
1407
|
+
// Share the public-start mutex. A consumer may call start in the await gap
|
|
1408
|
+
// after the rejected recorder stops; both paths must converge on one rrweb
|
|
1409
|
+
// instance rather than racing two fresh identities.
|
|
1410
|
+
if (state.startPromise)
|
|
1411
|
+
return state.startPromise;
|
|
1412
|
+
const startGeneration = ++state.startGeneration;
|
|
1413
|
+
let startPromise;
|
|
1414
|
+
startPromise = restartSessionReplayAfterConflictInternal(state, options, sessionId, startGeneration).finally(() => {
|
|
1415
|
+
if (state.startPromise === startPromise)
|
|
1416
|
+
state.startPromise = null;
|
|
1417
|
+
});
|
|
1418
|
+
state.startPromise = startPromise;
|
|
1419
|
+
return startPromise;
|
|
1420
|
+
}
|
|
1421
|
+
async function restartSessionReplayAfterConflictInternal(state, options, sessionId, startGeneration) {
|
|
1385
1422
|
if (options.shouldStart && !options.shouldStart()) {
|
|
1386
1423
|
return { started: false, reason: "disabled", sessionId, sampled: true };
|
|
1387
1424
|
}
|
|
@@ -1402,7 +1439,7 @@ async function restartSessionReplayAfterConflict(state, options, sessionId) {
|
|
|
1402
1439
|
sampled: true,
|
|
1403
1440
|
};
|
|
1404
1441
|
}
|
|
1405
|
-
return startSessionReplayRecorder(state, options, sessionId, true, initialProperties);
|
|
1442
|
+
return startSessionReplayRecorder(state, options, sessionId, true, initialProperties, startGeneration);
|
|
1406
1443
|
}
|
|
1407
1444
|
function installUrlMonitor(state) {
|
|
1408
1445
|
if (!state.options || state.restoreUrlMonitor)
|
|
@@ -2178,8 +2215,13 @@ export async function startSessionReplay(options = {}) {
|
|
|
2178
2215
|
}
|
|
2179
2216
|
if (state.startPromise)
|
|
2180
2217
|
return state.startPromise;
|
|
2218
|
+
// This is a new caller-initiated recording episode. A prior episode's
|
|
2219
|
+
// conflict-loop guard must not prevent this one from recovering once.
|
|
2220
|
+
state.automaticConflictRestartAttempted = false;
|
|
2221
|
+
state.transientClientErrorFailures = 0;
|
|
2222
|
+
const startGeneration = ++state.startGeneration;
|
|
2181
2223
|
let startPromise;
|
|
2182
|
-
startPromise = startSessionReplayRecorder(state, normalized, sessionId, sampled, initialProperties).finally(() => {
|
|
2224
|
+
startPromise = startSessionReplayRecorder(state, normalized, sessionId, sampled, initialProperties, startGeneration).finally(() => {
|
|
2183
2225
|
if (state.startPromise === startPromise) {
|
|
2184
2226
|
state.startPromise = null;
|
|
2185
2227
|
}
|
|
@@ -2187,7 +2229,7 @@ export async function startSessionReplay(options = {}) {
|
|
|
2187
2229
|
state.startPromise = startPromise;
|
|
2188
2230
|
return startPromise;
|
|
2189
2231
|
}
|
|
2190
|
-
async function startSessionReplayRecorder(state, normalized, sessionId, sampled, initialProperties) {
|
|
2232
|
+
async function startSessionReplayRecorder(state, normalized, sessionId, sampled, initialProperties, startGeneration) {
|
|
2191
2233
|
if (state.active && state.replayId) {
|
|
2192
2234
|
return {
|
|
2193
2235
|
started: true,
|
|
@@ -2204,6 +2246,9 @@ async function startSessionReplayRecorder(state, normalized, sessionId, sampled,
|
|
|
2204
2246
|
catch {
|
|
2205
2247
|
return { started: false, reason: "import-failed", sessionId, sampled };
|
|
2206
2248
|
}
|
|
2249
|
+
if (state.startGeneration !== startGeneration) {
|
|
2250
|
+
return { started: false, reason: "disabled", sessionId, sampled };
|
|
2251
|
+
}
|
|
2207
2252
|
if (normalized.shouldStart && !normalized.shouldStart()) {
|
|
2208
2253
|
return { started: false, reason: "disabled", sessionId, sampled };
|
|
2209
2254
|
}
|
|
@@ -2232,6 +2277,19 @@ async function startSessionReplayRecorder(state, normalized, sessionId, sampled,
|
|
|
2232
2277
|
};
|
|
2233
2278
|
}
|
|
2234
2279
|
}
|
|
2280
|
+
// stopSessionReplay may be called while the duplicate-tab probe is waiting.
|
|
2281
|
+
// Recheck both cancellation and the caller's live eligibility before rrweb
|
|
2282
|
+
// is activated so a deferred start cannot escape a route/auth teardown.
|
|
2283
|
+
if (state.startGeneration !== startGeneration ||
|
|
2284
|
+
(normalized.shouldStart && !normalized.shouldStart())) {
|
|
2285
|
+
try {
|
|
2286
|
+
replayChannel?.close();
|
|
2287
|
+
}
|
|
2288
|
+
catch {
|
|
2289
|
+
// best-effort cleanup
|
|
2290
|
+
}
|
|
2291
|
+
return { started: false, reason: "disabled", sessionId, sampled };
|
|
2292
|
+
}
|
|
2235
2293
|
state.options = normalized;
|
|
2236
2294
|
state.replayId = replaySession.replayId;
|
|
2237
2295
|
state.startedAtMs = replaySession.startedAtMs;
|
|
@@ -2328,6 +2386,10 @@ async function startSessionReplayRecorder(state, normalized, sessionId, sampled,
|
|
|
2328
2386
|
}
|
|
2329
2387
|
export async function stopSessionReplay(reason = "manual") {
|
|
2330
2388
|
const state = getState();
|
|
2389
|
+
// Invalidate an import/probe that has not set `active` yet. Without this,
|
|
2390
|
+
// stop during the duplicated-tab claim window was a no-op and rrweb started
|
|
2391
|
+
// after the caller believed recording had been disabled.
|
|
2392
|
+
state.startGeneration += 1;
|
|
2331
2393
|
if (!state.active)
|
|
2332
2394
|
return;
|
|
2333
2395
|
// Restore console/fetch/XHR before tearing down the recorder: the restore
|