@agent-native/core 0.219.0 → 0.220.0-nightly-20261023212848

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 (97) hide show
  1. package/dist/action.d.ts +23 -3
  2. package/dist/action.js +58 -3
  3. package/dist/agent/abort-reasons.d.ts +6 -0
  4. package/dist/agent/abort-reasons.js +6 -0
  5. package/dist/agent/execution-fence.js +5 -1
  6. package/dist/agent/production-agent.d.ts +22 -6
  7. package/dist/agent/production-agent.js +136 -37
  8. package/dist/agent/run-manager.js +92 -44
  9. package/dist/agent/run-store.d.ts +1 -0
  10. package/dist/agent/run-store.js +260 -31
  11. package/dist/agent/run-terminal-tracking.d.ts +29 -0
  12. package/dist/agent/run-terminal-tracking.js +56 -0
  13. package/dist/agent/run-turn-id-header.d.ts +9 -0
  14. package/dist/agent/run-turn-id-header.js +13 -0
  15. package/dist/agent/types.d.ts +11 -0
  16. package/dist/chat-threads/store.d.ts +23 -6
  17. package/dist/chat-threads/store.js +119 -36
  18. package/dist/cli/amplify-stream.js +1 -1
  19. package/dist/client/agent-chat/index.d.ts +2 -1
  20. package/dist/client/agent-chat/index.js +2 -1
  21. package/dist/client/agent-chat.d.ts +2 -0
  22. package/dist/client/agent-chat.js +31 -5
  23. package/dist/client/chat/agentkit-agent-native.js +8 -1
  24. package/dist/client/chat/agentkit-protocol.js +7 -1
  25. package/dist/client/chat/run-outcome-telemetry.js +1 -0
  26. package/dist/client/chat/run-outcome.d.ts +5 -0
  27. package/dist/client/chat/runtime.d.ts +34 -1
  28. package/dist/client/chat/runtime.js +96 -12
  29. package/dist/client/chat/turn-submitted-telemetry.d.ts +4 -0
  30. package/dist/client/chat/turn-submitted-telemetry.js +39 -0
  31. package/dist/client/chat/turn-submitted.d.ts +39 -0
  32. package/dist/client/chat/turn-submitted.js +16 -0
  33. package/dist/client/route-chunk-recovery.d.ts +3 -8
  34. package/dist/client/route-chunk-recovery.js +11 -9
  35. package/dist/client/use-chat-thread-list.d.ts +2 -0
  36. package/dist/client/use-chat-thread-list.js +48 -2
  37. package/dist/client/use-chat-threads.d.ts +13 -0
  38. package/dist/client/use-chat-threads.js +59 -4
  39. package/dist/collab/routes.d.ts +2 -2
  40. package/dist/db/client.d.ts +1 -0
  41. package/dist/db/client.js +28 -18
  42. package/dist/db/schema-snapshot.generated.js +5 -0
  43. package/dist/identity/rekey.d.ts +2 -0
  44. package/dist/identity/rekey.js +19 -0
  45. package/dist/index.d.ts +1 -1
  46. package/dist/index.js +1 -1
  47. package/dist/mcp/agent-connected.d.ts +5 -0
  48. package/dist/mcp/agent-connected.js +10 -3
  49. package/dist/mcp/analytics.d.ts +14 -1
  50. package/dist/mcp/analytics.js +54 -2
  51. package/dist/mcp/embed-app.js +2 -1
  52. package/dist/mcp/oauth-route.js +56 -1
  53. package/dist/notifications/routes.d.ts +1 -1
  54. package/dist/observability/routes.d.ts +7 -7
  55. package/dist/observability/traces.d.ts +2 -0
  56. package/dist/observability/traces.js +11 -2
  57. package/dist/provider-api/actions/custom-provider-registration.d.ts +16 -16
  58. package/dist/provider-api/actions/provider-api.d.ts +13 -13
  59. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  60. package/dist/resources/handlers.d.ts +1 -1
  61. package/dist/review/index.d.ts +1 -1
  62. package/dist/review/index.js +1 -1
  63. package/dist/review/suggestions/actions.js +25 -17
  64. package/dist/review/suggestions/store.d.ts +14 -1
  65. package/dist/review/suggestions/store.js +16 -3
  66. package/dist/review/suggestions/types.d.ts +15 -1
  67. package/dist/scripts/chat/search-chats.js +14 -2
  68. package/dist/server/agent-chat/browser-team-tools.js +39 -6
  69. package/dist/server/agent-chat/script-entries.js +44 -9
  70. package/dist/server/agent-chat-plugin.d.ts +2 -0
  71. package/dist/server/agent-chat-plugin.js +66 -16
  72. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  73. package/dist/server/agent-engine-default-model-route.d.ts +1 -1
  74. package/dist/server/first-touch-route.d.ts +2 -2
  75. package/dist/shared/route-chunk-recovery-bootstrap.d.ts +9 -0
  76. package/dist/shared/route-chunk-recovery-bootstrap.js +25 -0
  77. package/dist/sharing/actions/list-resource-shares.d.ts +1 -1
  78. package/dist/templates/chat/.agents/skills/actions/SKILL.md +1 -0
  79. package/dist/templates/default/.agents/skills/actions/SKILL.md +1 -0
  80. package/dist/templates/factory/.agents/skills/review-prs/SKILL.md +27 -3
  81. package/dist/templates/headless/.agents/skills/actions/SKILL.md +1 -0
  82. package/dist/templates/workspace-core/.agents/skills/actions/SKILL.md +1 -0
  83. package/dist/templates/workspace-core/.agents/skills/external-agents/references/mcp-apps-embedding.md +12 -5
  84. package/dist/tracking/providers.js +3 -0
  85. package/dist/triggers/actions/manage-automation.d.ts +2 -2
  86. package/docs/content/external-agents.mdx +1 -1
  87. package/docs/content/mcp-apps.mdx +3 -3
  88. package/docs/content/mcp-protocol.mdx +1 -1
  89. package/docs/content/sharing.mdx +1 -0
  90. package/docs/content/template-assets-integrations.mdx +5 -3
  91. package/package.json +3 -3
  92. package/src/templates/chat/.agents/skills/actions/SKILL.md +1 -0
  93. package/src/templates/default/.agents/skills/actions/SKILL.md +1 -0
  94. package/src/templates/factory/.agents/skills/review-prs/SKILL.md +27 -3
  95. package/src/templates/headless/.agents/skills/actions/SKILL.md +1 -0
  96. package/src/templates/workspace-core/.agents/skills/actions/SKILL.md +1 -0
  97. package/src/templates/workspace-core/.agents/skills/external-agents/references/mcp-apps-embedding.md +12 -5
@@ -16,6 +16,6 @@ export declare function createNotificationsHandler(): import("h3").EventHandlerW
16
16
  } | {
17
17
  count?: undefined;
18
18
  updated?: undefined;
19
- error?: undefined;
20
19
  ok: boolean;
20
+ error?: undefined;
21
21
  }>>;
@@ -27,43 +27,43 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
27
27
  thumbsUpRate: number;
28
28
  avgEvalScore: number;
29
29
  } | {
30
- ok?: undefined;
31
30
  error: string;
32
31
  message: string;
33
32
  summary?: undefined;
34
33
  spans?: undefined;
35
- } | {
36
- error?: undefined;
37
34
  ok?: undefined;
35
+ } | {
38
36
  message?: undefined;
39
37
  summary: import("./types.js").TraceSummary;
40
38
  spans: import("./types.js").TraceSpan[];
41
- } | {
42
39
  error?: undefined;
43
40
  ok?: undefined;
41
+ } | {
44
42
  message?: undefined;
45
43
  summary?: undefined;
46
44
  spans?: undefined;
47
45
  traceMissing: true;
48
46
  id: string;
49
- } | {
50
47
  error?: undefined;
51
48
  ok?: undefined;
49
+ } | {
52
50
  message?: undefined;
53
51
  summary?: undefined;
54
52
  spans?: undefined;
55
53
  traceMissing?: undefined;
56
54
  id: string;
57
- } | {
55
+ error?: undefined;
58
56
  ok?: undefined;
57
+ } | {
59
58
  message?: undefined;
60
59
  summary?: undefined;
61
60
  spans?: undefined;
62
61
  error: any;
62
+ ok?: undefined;
63
63
  } | {
64
- error?: undefined;
65
64
  message?: undefined;
66
65
  summary?: undefined;
67
66
  spans?: undefined;
67
+ error?: undefined;
68
68
  ok: boolean;
69
69
  }>>;
@@ -37,6 +37,8 @@ export declare function instrumentAgentLoop(opts: {
37
37
  };
38
38
  runId: string;
39
39
  threadId: string | null;
40
+ /** The agent turn this run serves; omitted from events when unknown. */
41
+ turnId?: string;
40
42
  userId: string | null;
41
43
  config: ObservabilityConfig;
42
44
  spanName?: string;
@@ -211,6 +211,7 @@ function emitLlmGenerationTrackingEvent(args) {
211
211
  span_type: "llm_call",
212
212
  run_id: args.runId,
213
213
  thread_id: args.threadId,
214
+ turn_id: args.turnId,
214
215
  parent_span_id: args.parentSpanId,
215
216
  span_id: args.llmSpanId,
216
217
  model: args.model,
@@ -357,7 +358,7 @@ export async function getObservabilityConfig() {
357
358
  return { ...config, ...resolveInferredSentimentConfig(config) };
358
359
  }
359
360
  export async function instrumentAgentLoop(opts) {
360
- const { runAgentLoop, loopOpts, runId, threadId, userId, config } = opts;
361
+ const { runAgentLoop, loopOpts, runId, threadId, turnId, userId, config } = opts;
361
362
  const engineName = typeof loopOpts.engine?.name === "string"
362
363
  ? loopOpts.engine.name
363
364
  : undefined;
@@ -752,8 +753,13 @@ export async function instrumentAgentLoop(opts) {
752
753
  error_class: !isError
753
754
  ? null
754
755
  : explicitError
755
- ? "tool_error"
756
+ ? (event.errorClass ?? "tool_error")
756
757
  : "legacy_inferred_error",
758
+ outcome: event.outcomeUnknown
759
+ ? "unknown"
760
+ : event.completedSideEffect === true
761
+ ? "completed"
762
+ : "no_side_effect",
757
763
  });
758
764
  }
759
765
  recordAgentToolCall({
@@ -927,6 +933,7 @@ export async function instrumentAgentLoop(opts) {
927
933
  duration_ms: Math.max(0, runEnd - pending.startMs),
928
934
  status: "error",
929
935
  error_class: "interrupted",
936
+ outcome: "unknown",
930
937
  });
931
938
  }
932
939
  if (pending.otelSpan) {
@@ -1149,6 +1156,7 @@ export async function instrumentAgentLoop(opts) {
1149
1156
  emitLlmGenerationTrackingEvent({
1150
1157
  runId,
1151
1158
  threadId,
1159
+ turnId,
1152
1160
  userId,
1153
1161
  parentSpanId,
1154
1162
  llmSpanId: generation.spanId,
@@ -1263,6 +1271,7 @@ export async function instrumentAgentLoop(opts) {
1263
1271
  source: "agent_observability",
1264
1272
  run_id: runId,
1265
1273
  thread_id: threadId,
1274
+ turn_id: turnId,
1266
1275
  llm_calls: llmCallCount || undefined,
1267
1276
  follow_up_ms: usage?.followUpMs,
1268
1277
  follow_up_input_tokens: usage?.followUpInputTokens,
@@ -75,10 +75,9 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
75
75
  user: "user";
76
76
  }>>;
77
77
  }, z.core.$strip>>, {
78
- message?: undefined;
79
78
  id?: undefined;
80
- provider?: undefined;
81
- deleted?: undefined;
79
+ message?: undefined;
80
+ found?: undefined;
82
81
  providers: {
83
82
  id: string;
84
83
  label: string;
@@ -89,45 +88,46 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
89
88
  updatedAt: number;
90
89
  }[];
91
90
  count: number;
92
- found?: undefined;
91
+ provider?: undefined;
92
+ deleted?: undefined;
93
93
  registered?: undefined;
94
94
  label?: undefined;
95
95
  } | {
96
- message?: undefined;
97
96
  id?: undefined;
98
- count?: undefined;
99
- deleted?: undefined;
97
+ message?: undefined;
100
98
  providers?: undefined;
99
+ count?: undefined;
101
100
  found: boolean;
102
101
  provider: import("../custom-registry.js").CustomProviderConfig;
102
+ deleted?: undefined;
103
103
  registered?: undefined;
104
104
  label?: undefined;
105
105
  } | {
106
106
  message?: undefined;
107
- provider?: undefined;
108
- count?: undefined;
109
- deleted?: undefined;
110
107
  providers?: undefined;
108
+ count?: undefined;
109
+ provider?: undefined;
111
110
  found: boolean;
112
111
  id: string;
112
+ deleted?: undefined;
113
113
  registered?: undefined;
114
114
  label?: undefined;
115
115
  } | {
116
116
  message?: undefined;
117
- provider?: undefined;
118
- count?: undefined;
119
- providers?: undefined;
120
117
  found?: undefined;
118
+ providers?: undefined;
119
+ count?: undefined;
120
+ provider?: undefined;
121
121
  deleted: boolean;
122
122
  id: string;
123
123
  registered?: undefined;
124
124
  label?: undefined;
125
125
  } | {
126
- provider?: undefined;
126
+ found?: undefined;
127
+ providers?: undefined;
127
128
  count?: undefined;
129
+ provider?: undefined;
128
130
  deleted?: undefined;
129
- providers?: undefined;
130
- found?: undefined;
131
131
  registered: boolean;
132
132
  id: string;
133
133
  label: string;
@@ -316,9 +316,8 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
316
316
  notes?: string | undefined;
317
317
  scope?: "org" | "user" | undefined;
318
318
  }, {
319
- id?: undefined;
319
+ found?: undefined;
320
320
  deleted?: undefined;
321
- provider?: undefined;
322
321
  providers: {
323
322
  id: string;
324
323
  label: string;
@@ -329,46 +328,47 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
329
328
  updatedAt: number;
330
329
  }[];
331
330
  count: number;
332
- found?: undefined;
331
+ provider?: undefined;
333
332
  registered?: undefined;
333
+ id?: undefined;
334
334
  label?: undefined;
335
335
  message?: undefined;
336
336
  } | {
337
- id?: undefined;
338
337
  deleted?: undefined;
339
- count?: undefined;
340
338
  providers?: undefined;
339
+ count?: undefined;
341
340
  found: boolean;
342
341
  provider: import("../custom-registry.js").CustomProviderConfig;
343
342
  registered?: undefined;
343
+ id?: undefined;
344
344
  label?: undefined;
345
345
  message?: undefined;
346
346
  } | {
347
347
  deleted?: undefined;
348
- provider?: undefined;
349
- count?: undefined;
350
348
  providers?: undefined;
349
+ count?: undefined;
350
+ provider?: undefined;
351
351
  found: boolean;
352
352
  id: string;
353
353
  registered?: undefined;
354
354
  label?: undefined;
355
355
  message?: undefined;
356
356
  } | {
357
- provider?: undefined;
358
- count?: undefined;
359
- providers?: undefined;
360
357
  found?: undefined;
358
+ providers?: undefined;
359
+ count?: undefined;
360
+ provider?: undefined;
361
361
  deleted: boolean;
362
362
  id: string;
363
363
  registered?: undefined;
364
364
  label?: undefined;
365
365
  message?: undefined;
366
366
  } | {
367
+ found?: undefined;
367
368
  deleted?: undefined;
368
- provider?: undefined;
369
- count?: undefined;
370
369
  providers?: undefined;
371
- found?: undefined;
370
+ count?: undefined;
371
+ provider?: undefined;
372
372
  registered: boolean;
373
373
  id: string;
374
374
  label: string;
@@ -73,7 +73,6 @@ export declare function createProviderCorpusJobAction(options: CreateProviderCor
73
73
  offset?: unknown;
74
74
  limit?: unknown;
75
75
  }, {
76
- deleted?: undefined;
77
76
  jobs: {
78
77
  id: string;
79
78
  name: string;
@@ -84,6 +83,7 @@ export declare function createProviderCorpusJobAction(options: CreateProviderCor
84
83
  updatedAt: string;
85
84
  }[];
86
85
  total: number;
86
+ deleted?: undefined;
87
87
  jobId?: undefined;
88
88
  } | {
89
89
  jobs?: undefined;
@@ -91,9 +91,9 @@ export declare function createProviderCorpusJobAction(options: CreateProviderCor
91
91
  deleted: boolean;
92
92
  jobId: string;
93
93
  } | {
94
- deleted?: undefined;
95
94
  jobs?: undefined;
96
95
  total?: undefined;
96
+ deleted?: undefined;
97
97
  jobId?: undefined;
98
98
  hits: Record<string, unknown>[];
99
99
  offset: number;
@@ -39,8 +39,8 @@ export declare function handleUpdateResource(event: any): Promise<import("./stor
39
39
  error: string;
40
40
  }>;
41
41
  export declare function handleDeleteResource(event: any): Promise<{
42
- ok?: undefined;
43
42
  error: string;
43
+ ok?: undefined;
44
44
  } | {
45
45
  error?: undefined;
46
46
  ok: boolean;
@@ -6,6 +6,6 @@ export { __resetReviewableResourcesForTests, assertReviewableResourceAccess, get
6
6
  export { __resetReviewInitForTests, ensureReviewTables, getReviewCommentById, getReviewStatus, getReviewThreadSummary, getReviewThreadRoot, queryReviewComments, routeReviewThread, sendReviewThreadToAgent, } from "./store.js";
7
7
  export * from "./suggestions/types.js";
8
8
  export { registerSuggestionAdapter, getSuggestionAdapter, listSuggestionAdapters, __resetSuggestionAdaptersForTests, } from "./suggestions/registry.js";
9
- export { ensureSuggestionTables, getDecision, getSuggestion, getSuggestionByCreationKey, listSuggestions, __resetSuggestionTablesForTests, } from "./suggestions/store.js";
9
+ export { ensureSuggestionTables, getDecision, getSuggestion, getSuggestionByCreationKey, listSuggestions, rebaseSuggestion, __resetSuggestionTablesForTests, } from "./suggestions/store.js";
10
10
  export { suggestionActorKind, suggestionActorKindMatchesReceipt, } from "./suggestions/actor-kind.js";
11
11
  export type { GetReviewThreadSummaryInput, ReviewThreadSummary, } from "./store.js";
@@ -5,5 +5,5 @@ export { __resetReviewableResourcesForTests, assertReviewableResourceAccess, get
5
5
  export { __resetReviewInitForTests, ensureReviewTables, getReviewCommentById, getReviewStatus, getReviewThreadSummary, getReviewThreadRoot, queryReviewComments, routeReviewThread, sendReviewThreadToAgent, } from "./store.js";
6
6
  export * from "./suggestions/types.js";
7
7
  export { registerSuggestionAdapter, getSuggestionAdapter, listSuggestionAdapters, __resetSuggestionAdaptersForTests, } from "./suggestions/registry.js";
8
- export { ensureSuggestionTables, getDecision, getSuggestion, getSuggestionByCreationKey, listSuggestions, __resetSuggestionTablesForTests, } from "./suggestions/store.js";
8
+ export { ensureSuggestionTables, getDecision, getSuggestion, getSuggestionByCreationKey, listSuggestions, rebaseSuggestion, __resetSuggestionTablesForTests, } from "./suggestions/store.js";
9
9
  export { suggestionActorKind, suggestionActorKindMatchesReceipt, } from "./suggestions/actor-kind.js";
@@ -435,7 +435,7 @@ export const decideResourceSuggestion = defineAction({
435
435
  }
436
436
  return { suggestion: latest, decision };
437
437
  };
438
- const decide = (coordination) => db.transaction(async (tx) => {
438
+ const decideIn = async (tx, coordination) => {
439
439
  const current = await getSuggestion(args.id, tx);
440
440
  if (!current)
441
441
  throw new Error("Suggestion not found");
@@ -450,8 +450,7 @@ export const decideResourceSuggestion = defineAction({
450
450
  errorCode: "suggestion_conflict",
451
451
  });
452
452
  }
453
- if (!currentAdapter ||
454
- currentAdapter.version !== current.adapterVersion)
453
+ if (!currentAdapter || currentAdapter.version !== current.adapterVersion)
455
454
  throw new Error("Suggestion adapter version is unavailable");
456
455
  // Withdrawing never applies the suggestion, so a base that moved on
457
456
  // since the author last saw it is no conflict.
@@ -508,11 +507,14 @@ export const decideResourceSuggestion = defineAction({
508
507
  resourceId: current.resourceId,
509
508
  }, args.decision);
510
509
  }
511
- return {
512
- suggestion: await getSuggestion(current.id, tx),
513
- decision: prior.record,
514
- };
515
- });
510
+ const decided = await getSuggestion(current.id, tx);
511
+ if (!decided)
512
+ throw new Error("Decided suggestion disappeared");
513
+ return { suggestion: decided, decision: prior.record };
514
+ };
515
+ const decide = (coordination, options = {}) => options.transaction
516
+ ? decideIn(options.transaction, coordination)
517
+ : db.transaction((tx) => decideIn(tx, coordination));
516
518
  if (args.decision === "accepted" && adapter.coordinateDecision) {
517
519
  return adapter.coordinateDecision({
518
520
  resourceType: suggestion.resourceType,
@@ -842,7 +844,7 @@ export const decideResourceSuggestionProposal = defineAction({
842
844
  suggestions: suggestions,
843
845
  };
844
846
  };
845
- const decide = (coordination) => db.transaction(async (tx) => {
847
+ const decideIn = async (tx, coordination) => {
846
848
  const currentProposal = await getSuggestionProposal(tx, args.proposalId);
847
849
  if (!currentProposal)
848
850
  fail("Proposal not found", {
@@ -936,15 +938,20 @@ export const decideResourceSuggestionProposal = defineAction({
936
938
  proposal: currentProposal,
937
939
  suggestions: decided,
938
940
  };
939
- }).catch(async (error) => {
940
- const prior = await getProposalDecision(db, args.idempotencyKey);
941
- if (!prior)
942
- throw error;
943
- return db.transaction(async (tx) => {
944
- await assertReviewableResourceAccess(proposal.resourceType, proposal.resourceId, { ...ctx, transaction: tx }, "editor");
945
- return replayDecision(tx, prior);
941
+ };
942
+ // A failure in the adapter's transaction aborts it, so the receipt of a
943
+ // decision that won meanwhile can't be read here; the adapter replays.
944
+ const decide = (coordination, options = {}) => options.transaction
945
+ ? decideIn(options.transaction, coordination)
946
+ : db.transaction((tx) => decideIn(tx, coordination)).catch(async (error) => {
947
+ const prior = await getProposalDecision(db, args.idempotencyKey);
948
+ if (!prior)
949
+ throw error;
950
+ return db.transaction(async (tx) => {
951
+ await assertReviewableResourceAccess(proposal.resourceType, proposal.resourceId, { ...ctx, transaction: tx }, "editor");
952
+ return replayDecision(tx, prior);
953
+ });
946
954
  });
947
- });
948
955
  if (args.decision === "accepted" && adapter.coordinateDecision) {
949
956
  return adapter.coordinateDecision({
950
957
  resourceType: proposal.resourceType,
@@ -953,6 +960,7 @@ export const decideResourceSuggestionProposal = defineAction({
953
960
  operations: initial.operations,
954
961
  decision: args.decision,
955
962
  proposalDecision: true,
963
+ proposalMemberIds: members.map((member) => member.id),
956
964
  access,
957
965
  ctx: { ...ctx, suggestionAccess: access },
958
966
  }, decide);
@@ -20,7 +20,20 @@ export declare function getSuggestionAmendment(client: DbExec, key: string): Pro
20
20
  request: string;
21
21
  suggestion: ResourceSuggestion;
22
22
  }>;
23
- export declare function amendSuggestion(client: DbExec, before: ResourceSuggestion, operations: SuggestionOperation[], summary: string, idempotencyKey: string, request: string): Promise<ResourceSuggestion | null>;
23
+ export declare function amendSuggestion(client: DbExec, before: ResourceSuggestion, operations: SuggestionOperation[], summary: string, idempotencyKey: string, request: string, baseRevision?: string): Promise<ResourceSuggestion | null>;
24
+ /**
25
+ * Moves a pending suggestion onto `baseRevision` with `operations` that make
26
+ * the same change there, as when its resource was rewritten into an
27
+ * equivalent form. It is recorded as an amendment, so the suggestion's
28
+ * revision moves and anyone holding the old one refreshes before deciding.
29
+ * Null when the suggestion was decided or changed since `before` was read.
30
+ */
31
+ export declare function rebaseSuggestion(client: DbExec, before: ResourceSuggestion, input: {
32
+ operations: SuggestionOperation[];
33
+ baseRevision: string;
34
+ idempotencyKey: string;
35
+ reason: string;
36
+ }): Promise<ResourceSuggestion | null>;
24
37
  export declare function getSuggestion(suggestionId: string, client?: DbExec): Promise<ResourceSuggestion | null>;
25
38
  /** Loads several suggestions in two queries; missing ids come back as null. */
26
39
  export declare function getSuggestions(suggestionIds: readonly string[], client?: DbExec): Promise<(ResourceSuggestion | null)[]>;
@@ -205,11 +205,11 @@ export async function getSuggestionAmendment(client, key) {
205
205
  }
206
206
  : null;
207
207
  }
208
- export async function amendSuggestion(client, before, operations, summary, idempotencyKey, request) {
208
+ export async function amendSuggestion(client, before, operations, summary, idempotencyKey, request, baseRevision = before.baseRevision) {
209
209
  const now = new Date().toISOString();
210
210
  const claimed = await client.execute({
211
- sql: "UPDATE agent_review_suggestions SET revision = revision + 1, summary = ?, updated_at = ? WHERE id = ? AND status = 'pending' AND revision = ?",
212
- args: [summary, now, before.id, before.revision],
211
+ sql: "UPDATE agent_review_suggestions SET revision = revision + 1, summary = ?, base_revision = ?, updated_at = ? WHERE id = ? AND status = 'pending' AND revision = ?",
212
+ args: [summary, baseRevision, now, before.id, before.revision],
213
213
  });
214
214
  if (claimed.rowsAffected !== 1)
215
215
  return null;
@@ -239,6 +239,19 @@ export async function amendSuggestion(client, before, operations, summary, idemp
239
239
  });
240
240
  return after;
241
241
  }
242
+ /**
243
+ * Moves a pending suggestion onto `baseRevision` with `operations` that make
244
+ * the same change there, as when its resource was rewritten into an
245
+ * equivalent form. It is recorded as an amendment, so the suggestion's
246
+ * revision moves and anyone holding the old one refreshes before deciding.
247
+ * Null when the suggestion was decided or changed since `before` was read.
248
+ */
249
+ export function rebaseSuggestion(client, before, input) {
250
+ return amendSuggestion(client, before, input.operations, before.summary, input.idempotencyKey, JSON.stringify({
251
+ rebase: input.reason,
252
+ baseRevision: input.baseRevision,
253
+ }), input.baseRevision);
254
+ }
242
255
  export async function getSuggestion(suggestionId, client = getDbExec()) {
243
256
  await ensureSuggestionTables(client);
244
257
  const row = (await client.execute({
@@ -68,9 +68,23 @@ export interface SuggestionDecisionContext {
68
68
  operations: SuggestionOperation[];
69
69
  decision: SuggestionDecision;
70
70
  proposalDecision?: boolean;
71
+ /**
72
+ * The members a proposal decision decides, in the order it calls `apply`
73
+ * for them. `suggestion` is the first.
74
+ */
75
+ proposalMemberIds?: string[];
71
76
  access: SuggestionAccess;
72
77
  ctx?: Record<string, unknown>;
73
78
  }
79
+ export interface SuggestionDecisionRunOptions {
80
+ /**
81
+ * Runs the decision in this transaction instead of its own, so the
82
+ * decision commits or rolls back with the adapter's write. A decision that
83
+ * replays an earlier one returns without calling `apply`; an adapter whose
84
+ * write must not commit without the decision has to check for that.
85
+ */
86
+ transaction?: unknown;
87
+ }
74
88
  export interface SuggestionAdapter {
75
89
  kind: string;
76
90
  version: number;
@@ -83,7 +97,7 @@ export interface SuggestionAdapter {
83
97
  ctx?: Record<string, unknown>;
84
98
  }): Promise<void | SuggestionOperation[]> | void | SuggestionOperation[];
85
99
  preview?(context: SuggestionContext): Promise<unknown> | unknown;
86
- coordinateDecision?<T>(context: SuggestionDecisionContext, run: (coordination?: unknown) => Promise<T>): Promise<T>;
100
+ coordinateDecision?<T>(context: SuggestionDecisionContext, run: (coordination?: unknown, options?: SuggestionDecisionRunOptions) => Promise<T>): Promise<T>;
87
101
  finalizeProposalDecision?(context: {
88
102
  resourceType: string;
89
103
  resourceId: string;
@@ -31,6 +31,7 @@ Options:
31
31
  --limit N Max results (default: 20)
32
32
  --format json Output as JSON
33
33
  --includeArchived Also include archived chats (excluded by default)
34
+ --includeHidden Also include chats hidden by you (excluded by default)
34
35
  --help Show this help message
35
36
 
36
37
  Examples:
@@ -45,10 +46,19 @@ Examples:
45
46
  if (isNaN(limit) || limit < 1)
46
47
  fail("--limit must be a positive integer");
47
48
  const includeArchived = parsed.includeArchived === "true";
49
+ const includeHidden = parsed.includeHidden === "true";
48
50
  const query = parsed.query;
49
51
  const threads = query
50
- ? await searchThreads(owner, query, limit, { includeArchived })
51
- : await listThreads(owner, { limit, offset: 0, includeArchived });
52
+ ? await searchThreads(owner, query, limit, {
53
+ includeArchived,
54
+ includeHidden,
55
+ })
56
+ : await listThreads(owner, {
57
+ limit,
58
+ offset: 0,
59
+ includeArchived,
60
+ includeHidden,
61
+ });
52
62
  if (parsed.format === "json") {
53
63
  console.log(JSON.stringify({
54
64
  query: query ?? null,
@@ -60,6 +70,7 @@ Examples:
60
70
  updatedAt: t.updatedAt,
61
71
  pinnedAt: t.pinnedAt ?? null,
62
72
  archivedAt: t.archivedAt ?? null,
73
+ hiddenAt: t.hiddenAt ?? null,
63
74
  })),
64
75
  count: threads.length,
65
76
  }, null, 2));
@@ -80,6 +91,7 @@ Examples:
80
91
  const flags = [
81
92
  t.pinnedAt ? "pinned" : null,
82
93
  t.archivedAt ? "archived" : null,
94
+ t.hiddenAt ? "hidden" : null,
83
95
  ].filter(Boolean);
84
96
  console.log(` ${title}`);
85
97
  console.log(` ID: ${t.id} | ${msgs} | ${time}${flags.length ? ` | ${flags.join(", ")}` : ""}`);
@@ -1,9 +1,11 @@
1
1
  import { createHash } from "node:crypto";
2
+ import { setTimeout as delay } from "node:timers/promises";
2
3
  import { ACTION_CHAT_UI_AGENT_TEAM_PROGRESS_RENDERER, normalizeAgentTeamProgressResult, } from "../../action-ui.js";
4
+ import { fail } from "../../action.js";
3
5
  import { getActiveFileUploadProviderForRequest } from "../../file-upload/registry.js";
4
6
  import { areBuiltinMcpCapabilitiesSupported, setBuiltinMcpCapabilityEnabled, } from "../../mcp-client/index.js";
5
7
  import { getBuilderBrowserConnectUrlForOwner, resolveBuilderBranchProjectId, } from "../builder-browser.js";
6
- import { getRequestUserEmail } from "../request-context.js";
8
+ import { getRequestOrgId, getRequestUserEmail } from "../request-context.js";
7
9
  import { getMcpManagerForCurrentRequest } from "./mcp-glue.js";
8
10
  const MAX_EXTENSION_PROMOTION_CONTENT_CHARS = 200_000;
9
11
  const MAX_AGENT_TEAM_PROGRESS_TASKS = 3;
@@ -367,8 +369,35 @@ export function createBuilderBrowserTool(deps) {
367
369
  return entries;
368
370
  }
369
371
  export function createTeamTools(deps) {
372
+ const readTask = async (taskId, waitMs, context) => {
373
+ if (!Number.isInteger(waitMs) || waitMs < 0 || waitMs > 20_000)
374
+ fail("waitMs must be an integer between 0 and 20000.", {
375
+ errorCode: "invalid_input",
376
+ statusCode: 422,
377
+ });
378
+ const scope = {
379
+ ownerEmail: deps.getOwner(),
380
+ orgId: context?.orgId !== undefined
381
+ ? context.orgId
382
+ : (getRequestOrgId() ?? null),
383
+ };
384
+ const signal = context?.signal;
385
+ signal?.throwIfAborted();
386
+ const { getTask } = await import("../agent-teams.js");
387
+ const deadline = Date.now() + waitMs;
388
+ let task = await getTask(taskId, scope);
389
+ signal?.throwIfAborted();
390
+ while (task?.status === "running" && Date.now() < deadline) {
391
+ await delay(Math.min(500, deadline - Date.now()), undefined, { signal });
392
+ signal?.throwIfAborted();
393
+ task = await getTask(taskId, scope);
394
+ signal?.throwIfAborted();
395
+ }
396
+ return task;
397
+ };
370
398
  return {
371
399
  "agent-teams": {
400
+ dedupe: false,
372
401
  tool: {
373
402
  description: "Manage background tasks that run in their own task thread. Use action 'spawn' to start one, 'status' to check progress, 'read-result' to get a finished task's output, 'send' to message a running task, or 'list' to see all tasks. A successful spawn only means the task started and is running; do not report it as finished until status/read-result shows a terminal status. This is a background task, not a source-control branch.",
374
403
  parameters: {
@@ -403,6 +432,12 @@ export function createTeamTools(deps) {
403
432
  type: "string",
404
433
  description: "(send) Message to send to the sub-agent",
405
434
  },
435
+ waitMs: {
436
+ type: "integer",
437
+ minimum: 0,
438
+ maximum: 20000,
439
+ description: "(status, read-result) Wait up to this many milliseconds for a terminal task. Defaults to 0 (immediate snapshot). A deadline can return queued/running; it does not mean completion or resume the parent automatically.",
440
+ },
406
441
  },
407
442
  required: ["action"],
408
443
  },
@@ -423,7 +458,7 @@ export function createTeamTools(deps) {
423
458
  allowedValues: { action: ["status", "read-result", "list"] },
424
459
  description: "Plan mode allows listing tasks and reading their status or results.",
425
460
  },
426
- run: async (args) => {
461
+ run: async (args, context) => {
427
462
  const action = args.action;
428
463
  if (action === "spawn") {
429
464
  if (!args.task)
@@ -481,8 +516,7 @@ export function createTeamTools(deps) {
481
516
  if (action === "status") {
482
517
  if (!args.taskId)
483
518
  throw new Error("'taskId' is required for status");
484
- const { getTask } = await import("../agent-teams.js");
485
- const task = await getTask(args.taskId);
519
+ const task = await readTask(args.taskId, args.waitMs === undefined ? 0 : args.waitMs, context);
486
520
  if (!task)
487
521
  return JSON.stringify({ error: "Task not found" });
488
522
  return JSON.stringify({
@@ -500,8 +534,7 @@ export function createTeamTools(deps) {
500
534
  if (action === "read-result") {
501
535
  if (!args.taskId)
502
536
  throw new Error("'taskId' is required for read-result");
503
- const { getTask } = await import("../agent-teams.js");
504
- const task = await getTask(args.taskId);
537
+ const task = await readTask(args.taskId, args.waitMs === undefined ? 0 : args.waitMs, context);
505
538
  if (!task)
506
539
  return JSON.stringify({ error: "Task not found" });
507
540
  if (task.status === "running") {