Skip to content

feat(runtime): type Linear agent session events - #180

Merged
khaliqgant merged 2 commits into
mainfrom
linear-agent-session-runtime-types
Jun 2, 2026
Merged

khaliqgant merged 2 commits into
mainfrom
linear-agent-session-runtime-types

Conversation

@khaliqgant

@khaliqgant khaliqgant commented Jun 2, 2026 •

Copy link
Copy Markdown
Member

Summary

  • derive Linear agent webhook trigger names from @relayfile/adapter-linear so TriggerNameFor<'linear'> accepts AgentSessionEvent.created, AgentSessionEvent.prompted, and AppUserNotification.issueCommentMention
  • add defensive Linear event payload types for the cloud resource-wrap plus nested .payload container
  • export unwrapResourceRecord(payload) from @agentworkforce/runtime public entry so agents do not hand-copy the resource -> payload unwrap
  • add type/fixture coverage for the AR-70-style { resource: { payload: { body, issue_id, issue_identifier }}} container
  • bump @agentworkforce/persona-kit and @agentworkforce/runtime to 3.0.41 for publish after merge

Verification

  • corepack pnpm --filter @agentworkforce/persona-kit test (246/246)
  • corepack pnpm --filter @agentworkforce/runtime test (59/59)

Notes

The AgentSessionEvent leg is intentionally defensive because no live AgentSessionEvent record exists yet. The fallback issue-comment container is covered by the AR-70-style fixture. The workforce union narrows via unwrapResourceRecord(event.payload) output, not raw idealized payload fields; unwrapResourceRecord is exported from @agentworkforce/runtime.

Blocker

blocked-pending-npm-publish: @agentworkforce/persona-kit@3.0.41, @agentworkforce/runtime@3.0.41

blocked-pending-npm-publish: @relayfile/adapter-core@0.3.31, @relayfile/adapter-linear@0.3.10, @relayfile/relay-helpers@0.3.31

Runtime tests are green with the current installed adapter-linear for event names. This marker tracks the cross-repo Lane A package publish dependency before cloud can consume the new Linear agent activity writeback route.

@codeant-ai

codeant-ai Bot commented Jun 2, 2026

Copy link
Copy Markdown

CodeAnt AI is reviewing your PR.

@gemini-code-assist

Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@coderabbitai

coderabbitai Bot commented Jun 2, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@khaliqgant, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 51 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d55d328b-772f-40f1-a4bf-3ff5925a6550

📥 Commits

Reviewing files that changed from the base of the PR and between 746b918 and 54ff48d.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (10)
  • packages/persona-kit/package.json
  • packages/persona-kit/src/define.test.ts
  • packages/persona-kit/src/define.ts
  • packages/persona-kit/src/triggers.test.ts
  • packages/persona-kit/src/triggers.ts
  • packages/runtime/package.json
  • packages/runtime/src/define-agent.test.ts
  • packages/runtime/src/define-agent.ts
  • packages/runtime/src/index.ts
  • packages/runtime/src/types.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch linear-agent-session-runtime-types

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codeant-ai codeant-ai Bot added the size:L This PR changes 100-499 lines, ignoring generated files label Jun 2, 2026
}

export type WorkforceEvent = WorkforceCronEvent | WorkforceProviderEvent;
export function unwrapResourceRecord<T = unknown>(payload: unknown): T | unknown {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: The generic return type is effectively lost because T | unknown always collapses to unknown, so callers never get the typed result they requested from unwrapResourceRecord<T>(...). Change the signature to return T (or T | undefined if needed) so the helper preserves the generic contract. [api mismatch]

Severity Level: Major ⚠️
- ⚠️ Linear handlers lose static typing for unwrapped payloads.
- ⚠️ Agent authors require extra guards or type assertions.
Steps of Reproduction ✅
1. In `packages/runtime/src/types.ts:59-62`, `unwrapResourceRecord` is declared as `export
function unwrapResourceRecord<T = unknown>(payload: unknown): T | unknown { … }`.

2. Because `T` is unconstrained, the return type `T | unknown` is equivalent to `unknown`
in TypeScript, so any call like `unwrapResourceRecord<Foo>(...)` is statically typed as
`unknown`, ignoring `Foo`.

3. The helper is re‑exported from `packages/runtime/src/index.ts:8-11` (`export {
unwrapResourceRecord } from './types.js';`), and used in
`packages/runtime/src/define-agent.test.ts:70-38` where it is called as
`unwrapResourceRecord<LinearAgentSessionPayload>(event.payload)` and
`unwrapResourceRecord<{ body?: string; issue_id?: string; issue_identifier?: string }>({
resource: { … }})`.

4. In both usages, the generic argument (`LinearAgentSessionPayload` or the inline object
type) does not affect the inferred return type, which remains `unknown`, forcing callers
to rely on separate type guards or assertions instead of getting the requested generic
shape from `unwrapResourceRecord<T>(...)`.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** packages/runtime/src/types.ts
**Line:** 59:59
**Comment:**
	*Api Mismatch: The generic return type is effectively lost because `T | unknown` always collapses to `unknown`, so callers never get the typed result they requested from `unwrapResourceRecord<T>(...)`. Change the signature to return `T` (or `T | undefined` if needed) so the helper preserves the generic contract.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

payload: LinearAppUserNotificationEventPayload;
});

export type WorkforceEvent = WorkforceCronEvent | LinearAgentSessionEvent | WorkforceProviderEvent;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: This union includes both a specialized Linear event type and the broad WorkforceProviderEvent that still allows source: 'linear', so the broad member swallows the specialized one during narrowing and payload falls back to unknown in common event.source/event.type checks. Exclude Linear from the generic provider branch (or split provider variants by source) so Linear payload typing is actually preserved. [api mismatch]

Severity Level: Major ⚠️
- ⚠️ Linear events via handler() keep payload as unknown.
- ⚠️ Event narrowing by source and type loses specificity.
- ⚠️ Encourages unsafe `any` casts in Linear handlers.
Steps of Reproduction ✅
1. In `packages/runtime/src/types.ts:44-49`, `WorkforceProviderEvent` is defined with
`source: Exclude<WorkforceEventSource, 'cron'>;`, which includes `'linear'`, and `payload:
unknown`.

2. In `packages/runtime/src/types.ts:148-158`, `LinearAgentSessionEvent` is defined as a
union of two specialized Linear variants with `source: 'linear'`, specific `type` literals
(`'AgentSessionEvent.created' | 'AgentSessionEvent.prompted' |
'AppUserNotification.issueCommentMention'`), and strongly typed `payload` fields
(`LinearAgentSessionEventPayload` / `LinearAppUserNotificationEventPayload`).

3. In `packages/runtime/src/types.ts:160`, `WorkforceEvent` is declared as
`WorkforceCronEvent | LinearAgentSessionEvent | WorkforceProviderEvent`, so a Linear event
with `source: 'linear'` and `type: 'AgentSessionEvent.created'` satisfies both
`LinearAgentSessionEvent` and the generic `WorkforceProviderEvent` branch.

4. The public handler signature in `packages/runtime/src/types.ts:370` and
`packages/runtime/src/handler.ts:27` uses `event: WorkforceEvent`, so in a typical handler
following the documented pattern in `handler.ts:14-24` but checking `event.source ===
'linear'` and `event.type === 'AgentSessionEvent.created'`, TypeScript narrows `event` to
`LinearAgentSessionEvent | (WorkforceProviderEvent & { source: 'linear'; type:
'AgentSessionEvent.created' })`, making `event.payload` effectively
`LinearAgentSessionEventPayload | unknown` which collapses to `unknown` and prevents the
Linear specialization from surfacing under normal `source`/`type` narrowing.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** packages/runtime/src/types.ts
**Line:** 160:160
**Comment:**
	*Api Mismatch: This union includes both a specialized Linear event type and the broad `WorkforceProviderEvent` that still allows `source: 'linear'`, so the broad member swallows the specialized one during narrowing and `payload` falls back to `unknown` in common `event.source/event.type` checks. Exclude Linear from the generic provider branch (or split provider variants by source) so Linear payload typing is actually preserved.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

@codeant-ai

codeant-ai Bot commented Jun 2, 2026

Copy link
Copy Markdown

CodeAnt AI finished reviewing your PR.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 14 files

Re-trigger cubic

@khaliqgant
khaliqgant force-pushed the linear-agent-session-runtime-types branch from 1f49e7f to 54ff48d Compare June 2, 2026 20:23
@khaliqgant
khaliqgant merged commit c44741f into main Jun 2, 2026
2 checks passed
@khaliqgant
khaliqgant deleted the linear-agent-session-runtime-types branch June 2, 2026 20:26
@agent-relay-code

Copy link
Copy Markdown
Contributor

⚠️ pr-reviewer did not push — the PR branch advanced during the review, so fixes were withheld to avoid overwriting newer commits. Re-trigger the review once the branch settles. The notes below are advisory and were not pushed.

Reviewed PR #180 and fixed the runtime payload typing issue I found.

Changed:

  • packages/runtime/src/types.ts: unwrapResourceRecord<T> now returns the requested generic type, and Linear event payloads now support raw webhook records, Relayfile resource records, and wrapped resource containers.
  • packages/runtime/src/index.ts: exported the new Linear payload container types.
  • packages/runtime/src/define-agent.test.ts: added coverage for direct resource records passed through the shim.

Verification:

  • corepack pnpm --filter @agentworkforce/persona-kit test
  • corepack pnpm --filter @agentworkforce/runtime test
  • corepack pnpm run build
  • corepack pnpm run check

@agent-relay-code

Copy link
Copy Markdown
Contributor

Reviewed PR #180 against the provided diff and traced the Linear trigger/runtime type changes through persona-kit, runtime, examples, and workspace checks.

No source fixes were needed. I ran:

corepack pnpm install
corepack pnpm -r build
corepack pnpm run check

The workspace check completed successfully after the required build step that the workflow also runs before lint/typecheck/test.

@agent-relay-code

Copy link
Copy Markdown
Contributor

Reviewed PR #180 against the provided diff and traced the Linear trigger/type changes through persona-kit, runtime exports, narrowing, shim behavior, and tests. I did not find breakage requiring code edits.

Local verification passed:

  • corepack pnpm install --frozen-lockfile
  • corepack pnpm run build
  • corepack pnpm run check

@agent-relay-code

Copy link
Copy Markdown
Contributor

⚠️ pr-reviewer did not push — the PR branch advanced during the review, so fixes were withheld to avoid overwriting newer commits. Re-trigger the review once the branch settles. The notes below are advisory and were not pushed.

Reviewed PR #180 and fixed one runtime typing issue: unwrapResourceRecord<T>() now actually returns the requested generic type instead of collapsing to unknown, with a test assertion covering that API behavior.

Local verification completed:

  • corepack pnpm --filter @agentworkforce/persona-kit test
  • corepack pnpm --filter @agentworkforce/runtime test
  • corepack pnpm run build
  • corepack pnpm run check
  • final runtime tsc --noEmit

@agent-relay-code

Copy link
Copy Markdown
Contributor

Reviewed PR #180 and made one fix.

Changed packages/runtime/src/types.ts: unwrapResourceRecord<T> now actually returns T; the previous T | unknown collapsed to unknown, making the generic unusable for callers.

Updated packages/runtime/src/define-agent.test.ts so the test exercises the typed return directly.

Validation run locally:
corepack pnpm --filter @agentworkforce/runtime test
corepack pnpm --filter @agentworkforce/persona-kit test
corepack pnpm -r build
corepack pnpm run check

corepack pnpm run check passed after building workspace package outputs first.

@agent-relay-code

Copy link
Copy Markdown
Contributor

Reviewed PR #180 and fixed type issues in the Linear runtime surface.

Key fixes:

  • unwrapResourceRecord<T>() now actually returns T; previously T | unknown collapsed to unknown.
  • Linear action/activity string unions now preserve literal autocomplete instead of collapsing to plain string.
  • Linear AppUserNotification runtime narrowing now covers all recognized notification actions, not just issueCommentMention.
  • Linear special event types are now distributive, so defineAgent() can narrow payloads for specific declared Linear events.
  • Added compile-time coverage for non-comment Linear notification payload narrowing and typed resource unwrapping.

Verification run:

  • corepack pnpm --filter @agentworkforce/persona-kit test
  • corepack pnpm --filter @agentworkforce/runtime test
  • corepack pnpm -r build
  • corepack pnpm run check

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L This PR changes 100-499 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant