pi-harness-runtime 1.1.236 → 1.1.237
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/index.ts +55 -3
- package/package.json +1 -1
- package/packages/a2a-adapter/package.json +1 -1
- package/packages/agent-policy/package.json +1 -1
- package/packages/architecture-generator/package.json +1 -1
- package/packages/auth/package.json +1 -1
- package/packages/autonomous-refactor/package.json +1 -1
- package/packages/autonomous-runtime/package.json +1 -1
- package/packages/cache-strategy/package.json +1 -1
- package/packages/capability-registry/package.json +1 -1
- package/packages/checkpoint/package.json +1 -1
- package/packages/cli-plugin-sdk/package.json +1 -1
- package/packages/clipboard/package.json +1 -1
- package/packages/clipboard-plugin/package.json +1 -1
- package/packages/code-generation/package.json +1 -1
- package/packages/code-review/package.json +1 -1
- package/packages/codex-adapter/package.json +1 -1
- package/packages/codex-watcher/package.json +1 -1
- package/packages/config-capture/package.json +1 -1
- package/packages/context-compiler/package.json +1 -1
- package/packages/context-discovery/package.json +1 -1
- package/packages/context-manager/package.json +1 -1
- package/packages/cookie-sanitizer/package.json +1 -1
- package/packages/cost-optimizer/package.json +1 -1
- package/packages/dependency-analyzer/package.json +1 -1
- package/packages/django-plugin/package.json +1 -1
- package/packages/doc-generator/package.json +1 -1
- package/packages/e2e-tester/package.json +1 -1
- package/packages/evaluation-engine/package.json +1 -1
- package/packages/evaluation-runner/package.json +1 -1
- package/packages/event-bus/package.json +1 -1
- package/packages/event-store/package.json +1 -1
- package/packages/experience-replay/package.json +1 -1
- package/packages/feedback-collector/package.json +1 -1
- package/packages/file-copy-helper/package.json +1 -1
- package/packages/framework-detector/package.json +1 -1
- package/packages/framework-plugin-sdk/package.json +1 -1
- package/packages/frappe-plugin/package.json +1 -1
- package/packages/generic-web-plugin/package.json +1 -1
- package/packages/health-monitor/package.json +1 -1
- package/packages/intent-analyzer/package.json +1 -1
- package/packages/jev-judge/dist/index.d.ts +5 -3
- package/packages/jev-judge/dist/index.d.ts.map +1 -1
- package/packages/jev-judge/dist/index.js +3 -1
- package/packages/jev-judge/dist/index.js.map +1 -1
- package/packages/jev-judge/dist/task-intake.d.ts +71 -0
- package/packages/jev-judge/dist/task-intake.d.ts.map +1 -0
- package/packages/jev-judge/dist/task-intake.js +217 -0
- package/packages/jev-judge/dist/task-intake.js.map +1 -0
- package/packages/jev-judge/package.json +1 -1
- package/packages/jev-judge/src/index.ts +7 -4
- package/packages/jev-judge/src/task-intake.ts +281 -0
- package/packages/knowledge-graph/package.json +1 -1
- package/packages/knowledge-retrieval/package.json +1 -1
- package/packages/laravel-plugin/package.json +1 -1
- package/packages/learning-engine/package.json +1 -1
- package/packages/mcp-adapter/package.json +1 -1
- package/packages/memory-engine/package.json +1 -1
- package/packages/milestone-manager/package.json +1 -1
- package/packages/model-registry/package.json +1 -1
- package/packages/nextjs-plugin/package.json +1 -1
- package/packages/notification/package.json +1 -1
- package/packages/observability/package.json +1 -1
- package/packages/okf-indexer/package.json +1 -1
- package/packages/paperclip-integration/package.json +1 -1
- package/packages/performance-optimizer/package.json +1 -1
- package/packages/privilege-broker/package.json +1 -1
- package/packages/project-analyzer/package.json +1 -1
- package/packages/project-bootstrap/package.json +1 -1
- package/packages/projection-engine/package.json +1 -1
- package/packages/prompt-compiler/package.json +1 -1
- package/packages/prompt-versioning/package.json +1 -1
- package/packages/provider-adapter-sdk/package.json +1 -1
- package/packages/provider-router/package.json +1 -1
- package/packages/provider-selector/package.json +1 -1
- package/packages/providers/package.json +1 -1
- package/packages/qdrant-skills/package.json +1 -1
- package/packages/quota-manager/package.json +1 -1
- package/packages/rate-limiter/package.json +1 -1
- package/packages/react-vite-plugin/package.json +1 -1
- package/packages/release-manager/package.json +1 -1
- package/packages/requirement-compiler/package.json +1 -1
- package/packages/runtime/package.json +1 -1
- package/packages/scheduler/package.json +1 -1
- package/packages/scheduler-adapter/package.json +1 -1
- package/packages/session/package.json +1 -1
- package/packages/session-api/package.json +1 -1
- package/packages/session-export/package.json +1 -1
- package/packages/shared-context/package.json +1 -1
- package/packages/skill-mcp-client/package.json +1 -1
- package/packages/skill-registry/package.json +1 -1
- package/packages/skills/package.json +1 -1
- package/packages/sprint-planner/package.json +1 -1
- package/packages/subscription-engine/package.json +1 -1
- package/packages/task-compiler/package.json +1 -1
- package/packages/telegram/package.json +1 -1
- package/packages/tencentdb-memory/package.json +1 -1
- package/packages/tencentdb-sync/package.json +1 -1
- package/packages/test-data-generator/package.json +1 -1
- package/packages/test-generator/package.json +1 -1
- package/packages/todo-bd-sync/package.json +1 -1
- package/packages/token-estimation/package.json +1 -1
- package/packages/token-optimizer/package.json +1 -1
- package/packages/trajectory/package.json +1 -1
- package/packages/tui/package.json +1 -1
- package/packages/types/package.json +1 -1
- package/packages/webmcp-tester/package.json +1 -1
- package/packages/workflow-events/package.json +1 -1
- package/packages/workspace-scanner/package.json +1 -1
- package/packages/worktree/package.json +1 -1
- package/packages/write-review/package.json +1 -1
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task Intake - Automatic todo capture from user requests
|
|
3
|
+
*
|
|
4
|
+
* Uses Jev Yes/No judgments to determine:
|
|
5
|
+
* - Whether a user request should be tracked as work
|
|
6
|
+
* - Whether it duplicates existing work
|
|
7
|
+
* - Whether it modifies an existing requirement
|
|
8
|
+
*/
|
|
9
|
+
import { JevJudge } from "./index.js";
|
|
10
|
+
/**
|
|
11
|
+
* Task Intake Controller
|
|
12
|
+
*
|
|
13
|
+
* Evaluates user requests with Jev to determine if they should be
|
|
14
|
+
* captured as todos for automatic tracking.
|
|
15
|
+
*/
|
|
16
|
+
export class TaskIntakeController {
|
|
17
|
+
jev = null;
|
|
18
|
+
config;
|
|
19
|
+
lastRequest = null;
|
|
20
|
+
lastResult = null;
|
|
21
|
+
constructor(config) {
|
|
22
|
+
this.config = {
|
|
23
|
+
actionableThreshold: 0.7,
|
|
24
|
+
...config,
|
|
25
|
+
};
|
|
26
|
+
// Initialize Jev if API key is available
|
|
27
|
+
if (config.apiKey) {
|
|
28
|
+
this.jev = new JevJudge(config);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Check if Jev is available
|
|
33
|
+
*/
|
|
34
|
+
isAvailable() {
|
|
35
|
+
return this.jev !== null;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Evaluate a user request for task capture
|
|
39
|
+
*/
|
|
40
|
+
async evaluate(userMessage, existingTodos = []) {
|
|
41
|
+
// Deduplicate identical requests
|
|
42
|
+
if (userMessage === this.lastRequest && this.lastResult) {
|
|
43
|
+
return this.lastResult;
|
|
44
|
+
}
|
|
45
|
+
// Build state for Jev evaluation
|
|
46
|
+
const state = {
|
|
47
|
+
userMessage,
|
|
48
|
+
existingTodos,
|
|
49
|
+
requestCount: existingTodos.length,
|
|
50
|
+
};
|
|
51
|
+
// If Jev is not available, use simple heuristic
|
|
52
|
+
if (!this.jev) {
|
|
53
|
+
const result = this.simpleHeuristic(userMessage, existingTodos);
|
|
54
|
+
this.lastRequest = userMessage;
|
|
55
|
+
this.lastResult = result;
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
// Ask Jev multiple questions
|
|
60
|
+
const result = await this.jev.evaluate(state, {
|
|
61
|
+
is_actionable: {
|
|
62
|
+
type: "noul",
|
|
63
|
+
instructions: "Does the user message request concrete work or a specific outcome? Ignore greetings, thanks, or status questions.",
|
|
64
|
+
},
|
|
65
|
+
is_duplicate: {
|
|
66
|
+
type: "noul",
|
|
67
|
+
instructions: "Does the user message duplicate work already listed in existingTodos? Check for similar task names or goals.",
|
|
68
|
+
},
|
|
69
|
+
modifies_existing: {
|
|
70
|
+
type: "noul",
|
|
71
|
+
instructions: "Does the user message modify or clarify an existing requirement rather than add new work?",
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
const actionable = result.decisions.is_actionable.response.type === "noul"
|
|
75
|
+
? result.decisions.is_actionable.response.noul >= this.config.actionableThreshold
|
|
76
|
+
: false;
|
|
77
|
+
const isDuplicate = result.decisions.is_duplicate.response.type === "noul"
|
|
78
|
+
? result.decisions.is_duplicate.response.noul >= 0.5
|
|
79
|
+
: false;
|
|
80
|
+
const modifiesExisting = result.decisions.modifies_existing.response.type === "noul"
|
|
81
|
+
? result.decisions.modifies_existing.response.noul >= 0.5
|
|
82
|
+
: false;
|
|
83
|
+
// Determine recommended action
|
|
84
|
+
let action;
|
|
85
|
+
if (!actionable) {
|
|
86
|
+
action = "skip";
|
|
87
|
+
}
|
|
88
|
+
else if (modifiesExisting) {
|
|
89
|
+
action = "amend";
|
|
90
|
+
}
|
|
91
|
+
else if (isDuplicate) {
|
|
92
|
+
action = "skip";
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
action = "create";
|
|
96
|
+
}
|
|
97
|
+
const finalResult = {
|
|
98
|
+
actionable,
|
|
99
|
+
probability: result.decisions.is_actionable.response.type === "noul"
|
|
100
|
+
? result.decisions.is_actionable.response.noul
|
|
101
|
+
: 0,
|
|
102
|
+
isDuplicate,
|
|
103
|
+
modifiesExisting,
|
|
104
|
+
action,
|
|
105
|
+
};
|
|
106
|
+
this.lastRequest = userMessage;
|
|
107
|
+
this.lastResult = finalResult;
|
|
108
|
+
return finalResult;
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
// On Jev error, fall back to simple heuristic
|
|
112
|
+
const result = this.simpleHeuristic(userMessage, existingTodos);
|
|
113
|
+
this.lastRequest = userMessage;
|
|
114
|
+
this.lastResult = result;
|
|
115
|
+
return result;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Simple heuristic when Jev is not available
|
|
120
|
+
*/
|
|
121
|
+
simpleHeuristic(userMessage, existingTodos) {
|
|
122
|
+
const lower = userMessage.toLowerCase();
|
|
123
|
+
// Check for non-actionable patterns
|
|
124
|
+
const nonActionable = [
|
|
125
|
+
/^(hi|hello|hey|thanks?|thank you)/i,
|
|
126
|
+
/how are you/i,
|
|
127
|
+
/what('s| is) the status/i,
|
|
128
|
+
/can you help me/i,
|
|
129
|
+
/just checking/i,
|
|
130
|
+
];
|
|
131
|
+
for (const pattern of nonActionable) {
|
|
132
|
+
if (pattern.test(lower)) {
|
|
133
|
+
return {
|
|
134
|
+
actionable: false,
|
|
135
|
+
probability: 0,
|
|
136
|
+
isDuplicate: false,
|
|
137
|
+
modifiesExisting: false,
|
|
138
|
+
action: "skip",
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
// Check for actionable patterns
|
|
143
|
+
const actionablePatterns = [
|
|
144
|
+
/\bfix\b/i,
|
|
145
|
+
/\bimplement\b/i,
|
|
146
|
+
/\badd\b/i,
|
|
147
|
+
/\bremove\b/i,
|
|
148
|
+
/\bcreate\b/i,
|
|
149
|
+
/\bupdate\b/i,
|
|
150
|
+
/\bchange\b/i,
|
|
151
|
+
/\bplease\b/i,
|
|
152
|
+
/\bi need\b/i,
|
|
153
|
+
/\bi want\b/i,
|
|
154
|
+
/\bcan you\b/i,
|
|
155
|
+
/\bcould you\b/i,
|
|
156
|
+
];
|
|
157
|
+
let probability = 0;
|
|
158
|
+
for (const pattern of actionablePatterns) {
|
|
159
|
+
if (pattern.test(lower)) {
|
|
160
|
+
probability = Math.min(probability + 0.2, 0.8);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
// Check for duplicates
|
|
164
|
+
let isDuplicate = false;
|
|
165
|
+
for (const todo of existingTodos) {
|
|
166
|
+
const todoLower = todo.toLowerCase();
|
|
167
|
+
// Simple word overlap check
|
|
168
|
+
const words = lower.split(/\s+/).filter(w => w.length > 3);
|
|
169
|
+
const overlap = words.filter(w => todoLower.includes(w)).length;
|
|
170
|
+
if (overlap >= 2) {
|
|
171
|
+
isDuplicate = true;
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
const actionable = probability >= 0.3 && !isDuplicate;
|
|
176
|
+
return {
|
|
177
|
+
actionable,
|
|
178
|
+
probability,
|
|
179
|
+
isDuplicate,
|
|
180
|
+
modifiesExisting: false,
|
|
181
|
+
action: actionable ? "create" : "skip",
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Dispatch a capture request to the agent
|
|
186
|
+
*/
|
|
187
|
+
async requestCapture(userMessage, existingTodos = []) {
|
|
188
|
+
const result = await this.evaluate(userMessage, existingTodos);
|
|
189
|
+
if (result.action === "skip") {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
// Build a message to prompt the agent to create todos
|
|
193
|
+
let message = "Work detected in user request. ";
|
|
194
|
+
if (result.isDuplicate) {
|
|
195
|
+
message += "Potential duplicate detected. ";
|
|
196
|
+
}
|
|
197
|
+
if (result.modifiesExisting) {
|
|
198
|
+
message += "Existing task modification detected. ";
|
|
199
|
+
}
|
|
200
|
+
message += `Please capture this work in the todo list if not already tracked.`;
|
|
201
|
+
await this.config.dispatch(message);
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Reset state
|
|
205
|
+
*/
|
|
206
|
+
reset() {
|
|
207
|
+
this.lastRequest = null;
|
|
208
|
+
this.lastResult = null;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Create a task intake controller
|
|
213
|
+
*/
|
|
214
|
+
export function createTaskIntake(config) {
|
|
215
|
+
return new TaskIntakeController(config);
|
|
216
|
+
}
|
|
217
|
+
//# sourceMappingURL=task-intake.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-intake.js","sourceRoot":"","sources":["../src/task-intake.ts"],"names":[],"mappings":"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"}
|
|
@@ -39,7 +39,6 @@ import type {
|
|
|
39
39
|
JevEvaluationResult,
|
|
40
40
|
JevNoulResponse,
|
|
41
41
|
JevChoiceResponse,
|
|
42
|
-
JevScoreResponse,
|
|
43
42
|
ThresholdDecision,
|
|
44
43
|
} from "./types.js";
|
|
45
44
|
|
|
@@ -427,7 +426,7 @@ export type { TaskState, AutoContinueDecision, AutoContinueConfig } from "./auto
|
|
|
427
426
|
|
|
428
427
|
// Export WrapUpJudge
|
|
429
428
|
export { checkWrapUp, getTodoSummary } from "./wrap-up-judge.js";
|
|
430
|
-
export type {
|
|
429
|
+
export type { WrapUpResult } from "./wrap-up-judge.js";
|
|
431
430
|
|
|
432
431
|
// Export EnvironmentJudge
|
|
433
432
|
export { EnvironmentJudge } from "./environment-judge.js";
|
|
@@ -442,5 +441,9 @@ export { TodoContinuationController, createTodoContinuation } from "./continuati
|
|
|
442
441
|
export type { ContinuationConfig, ContinuationState, ContinuationResult } from "./continuation-controller.js";
|
|
443
442
|
|
|
444
443
|
// Export TodoProvider
|
|
445
|
-
export { createTodoProvider
|
|
446
|
-
export type { TodoProvider,
|
|
444
|
+
export { createTodoProvider } from "./todo-provider.js";
|
|
445
|
+
export type { TodoProvider, TodoAvailability, TodoItem, TodoStatus, TodoSnapshot, TodoContext } from "./todo-provider.js";
|
|
446
|
+
|
|
447
|
+
// Export Task Intake
|
|
448
|
+
export { TaskIntakeController, createTaskIntake } from "./task-intake.js";
|
|
449
|
+
export type { TaskIntakeConfig, TaskIntakeResult } from "./task-intake.js";
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task Intake - Automatic todo capture from user requests
|
|
3
|
+
*
|
|
4
|
+
* Uses Jev Yes/No judgments to determine:
|
|
5
|
+
* - Whether a user request should be tracked as work
|
|
6
|
+
* - Whether it duplicates existing work
|
|
7
|
+
* - Whether it modifies an existing requirement
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { JevJudge } from "./index.js";
|
|
11
|
+
import type { JevJudgeConfig } from "./types.js";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Task intake configuration
|
|
15
|
+
*/
|
|
16
|
+
export interface TaskIntakeConfig extends JevJudgeConfig {
|
|
17
|
+
/** Minimum noul threshold for capturing as actionable */
|
|
18
|
+
actionableThreshold?: number;
|
|
19
|
+
/** Dispatch function to send messages to the agent */
|
|
20
|
+
dispatch: (content: string) => Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Result of task intake evaluation
|
|
25
|
+
*/
|
|
26
|
+
export interface TaskIntakeResult {
|
|
27
|
+
/** Whether the request should be captured as actionable work */
|
|
28
|
+
actionable: boolean;
|
|
29
|
+
/** Probability that it's actionable (0-1) */
|
|
30
|
+
probability: number;
|
|
31
|
+
/** Whether it duplicates existing work */
|
|
32
|
+
isDuplicate: boolean;
|
|
33
|
+
/** Whether it modifies an existing requirement */
|
|
34
|
+
modifiesExisting: boolean;
|
|
35
|
+
/** Recommended action */
|
|
36
|
+
action: "create" | "skip" | "amend" | "investigate";
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Task Intake Controller
|
|
41
|
+
*
|
|
42
|
+
* Evaluates user requests with Jev to determine if they should be
|
|
43
|
+
* captured as todos for automatic tracking.
|
|
44
|
+
*/
|
|
45
|
+
export class TaskIntakeController {
|
|
46
|
+
private jev: JevJudge | null = null;
|
|
47
|
+
private config: Required<TaskIntakeConfig>;
|
|
48
|
+
private lastRequest: string | null = null;
|
|
49
|
+
private lastResult: TaskIntakeResult | null = null;
|
|
50
|
+
|
|
51
|
+
constructor(config: TaskIntakeConfig) {
|
|
52
|
+
this.config = {
|
|
53
|
+
actionableThreshold: 0.7,
|
|
54
|
+
...config,
|
|
55
|
+
} as Required<TaskIntakeConfig>;
|
|
56
|
+
|
|
57
|
+
// Initialize Jev if API key is available
|
|
58
|
+
if (config.apiKey) {
|
|
59
|
+
this.jev = new JevJudge(config as JevJudgeConfig);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Check if Jev is available
|
|
65
|
+
*/
|
|
66
|
+
isAvailable(): boolean {
|
|
67
|
+
return this.jev !== null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Evaluate a user request for task capture
|
|
72
|
+
*/
|
|
73
|
+
async evaluate(
|
|
74
|
+
userMessage: string,
|
|
75
|
+
existingTodos: string[] = []
|
|
76
|
+
): Promise<TaskIntakeResult> {
|
|
77
|
+
// Deduplicate identical requests
|
|
78
|
+
if (userMessage === this.lastRequest && this.lastResult) {
|
|
79
|
+
return this.lastResult;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Build state for Jev evaluation
|
|
83
|
+
const state = {
|
|
84
|
+
userMessage,
|
|
85
|
+
existingTodos,
|
|
86
|
+
requestCount: existingTodos.length,
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// If Jev is not available, use simple heuristic
|
|
90
|
+
if (!this.jev) {
|
|
91
|
+
const result = this.simpleHeuristic(userMessage, existingTodos);
|
|
92
|
+
this.lastRequest = userMessage;
|
|
93
|
+
this.lastResult = result;
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
// Ask Jev multiple questions
|
|
99
|
+
const result = await this.jev.evaluate(state, {
|
|
100
|
+
is_actionable: {
|
|
101
|
+
type: "noul",
|
|
102
|
+
instructions:
|
|
103
|
+
"Does the user message request concrete work or a specific outcome? Ignore greetings, thanks, or status questions.",
|
|
104
|
+
},
|
|
105
|
+
is_duplicate: {
|
|
106
|
+
type: "noul",
|
|
107
|
+
instructions:
|
|
108
|
+
"Does the user message duplicate work already listed in existingTodos? Check for similar task names or goals.",
|
|
109
|
+
},
|
|
110
|
+
modifies_existing: {
|
|
111
|
+
type: "noul",
|
|
112
|
+
instructions:
|
|
113
|
+
"Does the user message modify or clarify an existing requirement rather than add new work?",
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
const actionable = result.decisions.is_actionable.response.type === "noul"
|
|
118
|
+
? result.decisions.is_actionable.response.noul >= this.config.actionableThreshold
|
|
119
|
+
: false;
|
|
120
|
+
const isDuplicate = result.decisions.is_duplicate.response.type === "noul"
|
|
121
|
+
? result.decisions.is_duplicate.response.noul >= 0.5
|
|
122
|
+
: false;
|
|
123
|
+
const modifiesExisting = result.decisions.modifies_existing.response.type === "noul"
|
|
124
|
+
? result.decisions.modifies_existing.response.noul >= 0.5
|
|
125
|
+
: false;
|
|
126
|
+
|
|
127
|
+
// Determine recommended action
|
|
128
|
+
let action: TaskIntakeResult["action"];
|
|
129
|
+
if (!actionable) {
|
|
130
|
+
action = "skip";
|
|
131
|
+
} else if (modifiesExisting) {
|
|
132
|
+
action = "amend";
|
|
133
|
+
} else if (isDuplicate) {
|
|
134
|
+
action = "skip";
|
|
135
|
+
} else {
|
|
136
|
+
action = "create";
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const finalResult: TaskIntakeResult = {
|
|
140
|
+
actionable,
|
|
141
|
+
probability: result.decisions.is_actionable.response.type === "noul"
|
|
142
|
+
? result.decisions.is_actionable.response.noul
|
|
143
|
+
: 0,
|
|
144
|
+
isDuplicate,
|
|
145
|
+
modifiesExisting,
|
|
146
|
+
action,
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
this.lastRequest = userMessage;
|
|
150
|
+
this.lastResult = finalResult;
|
|
151
|
+
return finalResult;
|
|
152
|
+
} catch (err) {
|
|
153
|
+
// On Jev error, fall back to simple heuristic
|
|
154
|
+
const result = this.simpleHeuristic(userMessage, existingTodos);
|
|
155
|
+
this.lastRequest = userMessage;
|
|
156
|
+
this.lastResult = result;
|
|
157
|
+
return result;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Simple heuristic when Jev is not available
|
|
163
|
+
*/
|
|
164
|
+
private simpleHeuristic(
|
|
165
|
+
userMessage: string,
|
|
166
|
+
existingTodos: string[]
|
|
167
|
+
): TaskIntakeResult {
|
|
168
|
+
const lower = userMessage.toLowerCase();
|
|
169
|
+
|
|
170
|
+
// Check for non-actionable patterns
|
|
171
|
+
const nonActionable = [
|
|
172
|
+
/^(hi|hello|hey|thanks?|thank you)/i,
|
|
173
|
+
/how are you/i,
|
|
174
|
+
/what('s| is) the status/i,
|
|
175
|
+
/can you help me/i,
|
|
176
|
+
/just checking/i,
|
|
177
|
+
];
|
|
178
|
+
|
|
179
|
+
for (const pattern of nonActionable) {
|
|
180
|
+
if (pattern.test(lower)) {
|
|
181
|
+
return {
|
|
182
|
+
actionable: false,
|
|
183
|
+
probability: 0,
|
|
184
|
+
isDuplicate: false,
|
|
185
|
+
modifiesExisting: false,
|
|
186
|
+
action: "skip",
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Check for actionable patterns
|
|
192
|
+
const actionablePatterns = [
|
|
193
|
+
/\bfix\b/i,
|
|
194
|
+
/\bimplement\b/i,
|
|
195
|
+
/\badd\b/i,
|
|
196
|
+
/\bremove\b/i,
|
|
197
|
+
/\bcreate\b/i,
|
|
198
|
+
/\bupdate\b/i,
|
|
199
|
+
/\bchange\b/i,
|
|
200
|
+
/\bplease\b/i,
|
|
201
|
+
/\bi need\b/i,
|
|
202
|
+
/\bi want\b/i,
|
|
203
|
+
/\bcan you\b/i,
|
|
204
|
+
/\bcould you\b/i,
|
|
205
|
+
];
|
|
206
|
+
|
|
207
|
+
let probability = 0;
|
|
208
|
+
for (const pattern of actionablePatterns) {
|
|
209
|
+
if (pattern.test(lower)) {
|
|
210
|
+
probability = Math.min(probability + 0.2, 0.8);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Check for duplicates
|
|
215
|
+
let isDuplicate = false;
|
|
216
|
+
for (const todo of existingTodos) {
|
|
217
|
+
const todoLower = todo.toLowerCase();
|
|
218
|
+
// Simple word overlap check
|
|
219
|
+
const words = lower.split(/\s+/).filter(w => w.length > 3);
|
|
220
|
+
const overlap = words.filter(w => todoLower.includes(w)).length;
|
|
221
|
+
if (overlap >= 2) {
|
|
222
|
+
isDuplicate = true;
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const actionable = probability >= 0.3 && !isDuplicate;
|
|
228
|
+
|
|
229
|
+
return {
|
|
230
|
+
actionable,
|
|
231
|
+
probability,
|
|
232
|
+
isDuplicate,
|
|
233
|
+
modifiesExisting: false,
|
|
234
|
+
action: actionable ? "create" : "skip",
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Dispatch a capture request to the agent
|
|
240
|
+
*/
|
|
241
|
+
async requestCapture(
|
|
242
|
+
userMessage: string,
|
|
243
|
+
existingTodos: string[] = []
|
|
244
|
+
): Promise<void> {
|
|
245
|
+
const result = await this.evaluate(userMessage, existingTodos);
|
|
246
|
+
|
|
247
|
+
if (result.action === "skip") {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Build a message to prompt the agent to create todos
|
|
252
|
+
let message = "Work detected in user request. ";
|
|
253
|
+
|
|
254
|
+
if (result.isDuplicate) {
|
|
255
|
+
message += "Potential duplicate detected. ";
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (result.modifiesExisting) {
|
|
259
|
+
message += "Existing task modification detected. ";
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
message += `Please capture this work in the todo list if not already tracked.`;
|
|
263
|
+
|
|
264
|
+
await this.config.dispatch(message);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Reset state
|
|
269
|
+
*/
|
|
270
|
+
reset(): void {
|
|
271
|
+
this.lastRequest = null;
|
|
272
|
+
this.lastResult = null;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Create a task intake controller
|
|
278
|
+
*/
|
|
279
|
+
export function createTaskIntake(config: TaskIntakeConfig): TaskIntakeController {
|
|
280
|
+
return new TaskIntakeController(config);
|
|
281
|
+
}
|